ZQuest Classic Coverage Report


Directory: src/
File: src/gui/jwin.cpp
Date: 2024-09-12 17:48:44
Exec Total Coverage
Lines: 198 5684 3.5%
Functions: 16 151 10.6%
Branches: 251 4399 5.7%

Line Branch Exec Source
1 #include <ctype.h>
2 #include <cstring>
3 #include "base/zapp.h"
4 #include "base/zc_alleg.h"
5 #include <allegro/internal/aintern.h>
6 #include "gui/jwin.h"
7 #include "gui/editbox.h"
8 #include <iostream>
9 #include <sstream>
10 #include "base/zsys.h"
11 #include <stdio.h>
12 #include "base/util.h"
13 #include "pal.h"
14 #include "gui/tabpanel.h"
15 #include "gui/text_field.h"
16 #include "dialog/info.h"
17 #include "drawing.h"
18 using namespace util;
19 using std::string;
20 using std::istringstream;
21
22 void update_hw_screen();
23 extern int32_t zq_screen_w, zq_screen_h;
24 extern int32_t joystick_index;
25 int CheckerCol1 = 7, CheckerCol2 = 8;
26
27 int32_t abc_patternmatch = 1;
28
29 char abc_keypresses[1024] = {0};
30 void wipe_abc_keypresses() { memset(abc_keypresses, 0, 1024); }
31
32 /* these are provided for external use */
33 int32_t jwin_colors[jcMAX] =
34 {
35 0xC0C0C0,0xF0F0F0,0xD0D0D0,0x808080,0x404040,0x000000,
36 0x000080,0x00F0F0,0xFFFFFF,0xFFFFFF,0x000000,0x000080,0xFFFFFF
37 };
38
39 int32_t scheme[jcMAX] =
40 {
41 0xC0C0C0,0xF0F0F0,0xD0D0D0,0x808080,0x404040,0x000000,
42 0x000080,0x00F0F0,0xFFFFFF,0xFFFFFF,0x000000,0x000080,0xFFFFFF
43 };
44
45 int32_t jwin_pal[jcMAX] = {0};
46
47 // A pointer to this variable is used to identify the DIALOG belonging to
48 // the DialogRunner. It isn't used for anything else.
49 char newGuiMarker;
50
51 int32_t new_gui_event(DIALOG* d, guiEvent event)
52 {
53 for(int32_t i = 0; true; --d, ++i)
54 {
55 if(d->dp3 == &newGuiMarker)
56 {
57 d->d1 = i;
58 return d->proc(MSG_GUI_EVENT, d, event);
59 }
60 }
61
62 return -1;
63 }
64
65 void close_new_gui_dlg(DIALOG* d);
66
67 int32_t bound(int32_t x,int32_t low,int32_t high)
68 {
69 if(x<low) x=low;
70
71 if(x>high) x=high;
72
73 return x;
74 }
75 /*
76 float bound(float x,float low,float high)
77 {
78 if(x<low) x=low;
79 if(x>high) x=high;
80 return x;
81 }
82 */
83
84 int32_t get_selected_tab(TABPANEL* panel)
85 {
86 for(int32_t i=0; panel[i].text; ++i)
87 {
88 if((panel[i].flags&D_SELECTED)!=0)
89 return i;
90 }
91 return -1;
92 }
93
94 /* jwin_set_colors:
95 * Loads a set of colors in 0xRRGGBB or 256-color-indexed format
96 * into the current color scheme using the appropriate color depth
97 * conversions.
98 */
99 110 void jwin_set_colors(int32_t *colors)
100 {
101 110 int32_t i = 0;
102
103
1/2
✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
110 if(bitmap_color_depth(screen) == 8)
104 {
105 // use color indices
106
2/2
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 2310 times.
2420 for(; i<jcMAX; i++)
107 2310 scheme[i] = colors[i];
108 110 }
109 else
110 {
111 // 0xRRGGBB format
112 for(; i<jcMAX; i++)
113 scheme[i] = makecol(colors[i]>>16, (colors[i]>>8)&0xFF, colors[i]&0xFF);
114 }
115 110 }
116
117 /* jwin_set_dialog_color:
118 * Sets the foreground and background colors of all the objects in a dialog.
119 *
120 * Needs work!
121 */
122 void jwin_set_dialog_color(DIALOG *dialog)
123 {
124 int32_t c;
125
126 for(c=0; dialog[c].proc; c++)
127 {
128 dialog[c].fg = scheme[jcMEDDARK];
129 dialog[c].bg = scheme[jcBOX];
130 }
131 }
132
133 /* jwin_draw_frame:
134 * Draws a frame using the specified style.
135 */
136 void jwin_draw_frame(BITMAP *dest,int32_t x,int32_t y,int32_t w,int32_t h,int32_t style)
137 {
138 optional<int> c1,c2,c3,c4;
139
140 switch(style)
141 {
142 case FR_INVIS:
143 return;
144 case FR_BOX:
145 c1 = jcLIGHT;
146 c2 = jcMEDLT;
147 c3 = jcMEDDARK;
148 c4 = jcDARK;
149 break;
150
151 case FR_INV:
152 c1 = jcDARK;
153 c2 = jcMEDDARK;
154 c3 = jcMEDLT;
155 c4 = jcLIGHT;
156 break;
157
158 case FR_DEEP:
159 c1 = jcMEDDARK;
160 c2 = jcDARK;
161 c3 = jcMEDLT;
162 c4 = jcLIGHT;
163 break;
164
165 case FR_DARK:
166 c1 = jcDARK;
167 c2 = jcMEDDARK;
168 c3 = jcMEDDARK;
169 c4 = jcDARK;
170 break;
171
172 case FR_ETCHED:
173 c1 = jcMEDDARK;
174 c2 = jcLIGHT;
175 c3 = jcMEDDARK;
176 c4 = jcLIGHT;
177 break;
178
179 case FR_MEDDARK:
180 c1 = jcMEDDARK;
181 c2 = jcBOX;
182 c3 = jcBOX;
183 c4 = jcMEDDARK;
184 break;
185
186 case FR_MENU:
187 c1 = jcLIGHT;
188 c4 = jcMEDDARK;
189 break;
190 case FR_MENU_INV:
191 c1 = jcMEDDARK;
192 c2 = jcMEDDARK;
193 c3 = jcLIGHT;
194 c4 = jcLIGHT;
195 break;
196
197 case FR_WIN:
198 default:
199 c1 = jcMEDLT;
200 c2 = jcLIGHT;
201 c3 = jcMEDDARK;
202 c4 = jcDARK;
203 break;
204 }
205
206 if(c1) c1 = scheme[*c1];
207 if(c2) c2 = scheme[*c2];
208 if(c3) c3 = scheme[*c3];
209 if(c4) c4 = scheme[*c4];
210 switch (style)
211 {
212 case FR_RED:
213 c1 = 0xE4;
214 c2 = 0xEC;
215 c3 = 0xE4;
216 c4 = 0xEC;
217 break;
218 case FR_GREEN:
219 c1 = 0xE2;
220 c2 = 0xEA;
221 c3 = 0xE2;
222 c4 = 0xEA;
223 break;
224 }
225 if(c1)
226 {
227 hline(dest, vbound(x,0,dest->w-1), vbound(y,0,dest->h-1) , vbound(x+w-2, 0,dest->w-1), *c1);
228 vline(dest, vbound(x,0,dest->w-1), vbound(y+1,0,dest->h-1), vbound(y+h-2, 0, dest->h-1), *c1);
229 }
230 if(c2)
231 {
232 hline(dest, vbound(x+1,0,dest->w-1), vbound(y+1,0,dest->h-1), vbound(x+w-3,0,dest->w-1), *c2);
233 vline(dest, vbound(x+1,0,dest->w-1), vbound(y+2,0,dest->h-1), vbound(y+h-3,0,dest->h-1), *c2);
234 }
235 if(c3)
236 {
237 hline(dest, vbound(x+1,0,dest->w-1), vbound(y+h-2,0,dest->h-1), vbound(x+w-2,0,dest->w-1), *c3);
238 vline(dest, vbound(x+w-2,0,dest->w-1), vbound(y+1,0,dest->h-1), vbound(y+h-3,0,dest->h-1), *c3);
239 }
240 if(c4)
241 {
242
243 hline(dest, vbound(x,0,dest->w-1), vbound(y+h-1,0,dest->h-1), vbound(x+w-1,0, dest->w-1), *c4);
244 vline(dest, vbound(x+w-1,0,dest->w-1), vbound(y,0,dest->h-1), vbound(y+h-2,0,dest->h-1), *c4);
245 }
246 }
247 void jwin_draw_frag_frame(BITMAP* dest, int x1, int y1, int w, int h, int fw, int fh, int style)
248 {
249 int c1,c2,c3,c4;
250
251 switch(style)
252 {
253 case FR_BOX:
254 c1 = jcLIGHT;
255 c2 = jcMEDLT;
256 c3 = jcMEDDARK;
257 c4 = jcDARK;
258 break;
259
260 case FR_INV:
261 c1 = jcDARK;
262 c2 = jcMEDDARK;
263 c3 = jcMEDLT;
264 c4 = jcLIGHT;
265 break;
266
267 case FR_DEEP:
268 c1 = jcMEDDARK;
269 c2 = jcDARK;
270 c3 = jcMEDLT;
271 c4 = jcLIGHT;
272 break;
273
274 case FR_DARK:
275 c1 = jcDARK;
276 c2 = jcMEDDARK;
277 c3 = jcMEDDARK;
278 c4 = jcDARK;
279 break;
280
281 case FR_ETCHED:
282 c1 = jcMEDDARK;
283 c2 = jcLIGHT;
284 c3 = jcMEDDARK;
285 c4 = jcLIGHT;
286 break;
287
288 case FR_MEDDARK:
289 c1 = jcMEDDARK;
290 c2 = jcBOX;
291 c3 = jcBOX;
292 c4 = jcMEDDARK;
293 break;
294
295 case FR_WIN:
296 default:
297 c1 = jcMEDLT;
298 c2 = jcLIGHT;
299 c3 = jcMEDDARK;
300 c4 = jcDARK;
301 break;
302 }
303
304 int xc = x1+fw-1;
305 int yc = y1+fh-1;
306 int x2 = x1+w-1;
307 int y2 = y1+h-1;
308
309 rectfill(dest, x1, y1, x2, yc, vc(0));
310 rectfill(dest, x1, yc, xc, y2, vc(0));
311
312 hline(dest, x1-2, y1-2, x2+2, scheme[c1]);
313 hline(dest, x1-1, y1-1, x2+1, scheme[c2]);
314
315 vline(dest, x1-2, y1-2, y2+2, scheme[c1]);
316 vline(dest, x1-1, y1-1, y2+1, scheme[c2]);
317
318 hline(dest, x1-2, y2+2, xc+2, scheme[c3]);
319 hline(dest, x1-1, y2+1, xc+1, scheme[c4]);
320
321 vline(dest, x2+2, y1-2, yc+2, scheme[c3]);
322 vline(dest, x2+1, y1-1, yc+1, scheme[c4]);
323
324 hline(dest, xc+2, yc+2, x2+2, scheme[c3]);
325 hline(dest, xc+1, yc+1, x2+1, scheme[c4]);
326
327 vline(dest, xc+2, yc+2, y2+2, scheme[c3]);
328 vline(dest, xc+1, yc+1, y2+1, scheme[c4]);
329 }
330 void jwin_draw_minimap_frame(BITMAP *dest,int x,int y,int w,int h,int scrsz,int style)
331 {
332 jwin_draw_frag_frame(dest,x,y,w,h,scrsz*8,scrsz*8,style);
333 }
334
335 /* jwin_draw_win:
336 * Draws a window -- a box with a frame.
337 */
338 void jwin_draw_win(BITMAP *dest,int32_t x,int32_t y,int32_t w,int32_t h,int32_t frame)
339 {
340 rectfill(dest,zc_max(x,0),zc_max(y,0),zc_min(x+w-1, dest->w-1),zc_min(y+h-1, dest->h-1),scheme[jcBOX]);
341 jwin_draw_frame(dest, x, y, w, h, frame);
342 }
343
344 /* jwin_draw_button:
345 * Helper function for buttons.
346 * Draws a box with a frame that depends on "state":
347 * 0: normal border (slightly different than window border)
348 * 1: inverted border
349 * 2: dark border
350 * 3: medium dark border
351 */
352 void jwin_draw_button(BITMAP *dest,int32_t x,int32_t y,int32_t w,int32_t h,int32_t state,int32_t type)
353 {
354 int32_t frame = FR_BOX;
355
356 if(type==1)
357 {
358 frame=FR_WIN;
359 }
360
361 switch(state)
362 {
363 case 1:
364 frame = FR_INV;
365 break;
366
367 case 2:
368 frame = FR_DARK;
369 break;
370
371 case 3:
372 frame = FR_MEDDARK;
373 break;
374 }
375
376 jwin_draw_win(dest, x, y, w, h, frame);
377 }
378
379 /* mix_value:
380 * Returns a mix of the values c1 and c2 with pos==0 being c1,
381 * pos==max being c2, pos==max/2 being half way between c1 and c2, etc.
382 */
383 int32_t mix_value(int32_t c1,int32_t c2,int32_t pos,int32_t max)
384 {
385 if(max<=0)
386 return c1;
387
388 return (c2 - c1) * pos / max + c1;
389 }
390
391 /* mix_color:
392 * Returns a mix of the colors c1 and c2 with pos==0 being c1,
393 * pos==max being c2, pos==max/2 being half way between c1 and c2, etc.
394 *
395 static int32_t mix_color(int32_t c1,int32_t c2,int32_t pos,int32_t max)
396 {
397 int32_t c;
398
399 if(bitmap_color_depth(screen) == 8)
400 c = mix_value(c1, c2, pos, max);
401 else
402 {
403 int32_t r = mix_value(getr(c1), getr(c2), pos, max);
404 int32_t g = mix_value(getg(c1), getg(c2), pos, max);
405 int32_t b = mix_value(getb(c1), getb(c2), pos, max);
406 c = makecol(r,g,b);
407 }
408
409 return c;
410 }
411 */
412
413 char *shorten_string(char *dest, char const* src, FONT *usefont, int32_t maxchars, int32_t maxwidth)
414 {
415 strncpy(dest,src,maxchars);
416 dest[maxchars-1]='\0';
417 int32_t len=(int32_t)strlen(dest);
418 int32_t width=text_length(usefont, dest);
419 dest[len]=0;
420
421 while(width>maxwidth && len>4)
422 {
423 dest[len-4] = '.';
424 dest[len-3] = '.';
425 dest[len-2] = '.';
426 dest[len-1] = 0;
427 len--;
428 width=text_length(usefont, dest);
429 }
430
431 return dest;
432 }
433
434 void jwin_draw_titlebar(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, const char *str, bool draw_button, bool helpbtn)
435 {
436 char buf[512];
437 int32_t len = (int32_t)strlen(str);
438 int32_t length = text_length(font,str);
439 int32_t height = text_height(font);
440
441 int32_t tx = x + 2;
442 int32_t ty = y + (h-height)/2;
443 PALETTE temp_pal;
444 get_palette(temp_pal);
445 dither_rect(dest, &temp_pal, x, y, x+w-1, y+h-1,
446 makecol15(temp_pal[scheme[jcTITLEL]].r,
447 temp_pal[scheme[jcTITLEL]].g,
448 temp_pal[scheme[jcTITLEL]].b),
449 makecol15(temp_pal[scheme[jcTITLER]].r,
450 temp_pal[scheme[jcTITLER]].g,
451 temp_pal[scheme[jcTITLER]].b),
452 scheme[jcTITLEL], scheme[jcTITLER]);
453
454
455 if(len>509)
456 len=509;
457
458 strncpy(buf,str,len);
459 buf[len]=0;
460
461 // this part needs work
462
463 if(length>w-20)
464 {
465 while(length>w-20 && len>1)
466 {
467 buf[len-4] = '.';
468 buf[len-3] = '.';
469 buf[len-2] = '.';
470 buf[len-1] = 0;
471 len--;
472 length = text_length(font,buf);
473 }
474 }
475
476 textout_ex(dest,font,buf,tx,ty,scheme[jcTITLEFG],-1);
477
478 if(draw_button)
479 {
480 draw_x_button(dest, x + w - 18, y+2, 0);
481 }
482
483 if(helpbtn)
484 {
485 draw_question_button(dest, x + w - (draw_button ? 36 : 18), y+2, 0);
486 }
487
488 }
489
490 void draw_question_button(BITMAP* dest, int32_t x, int32_t y, int32_t state)
491 {
492 int32_t c = scheme[jcBOXFG];
493
494 jwin_draw_button(dest,x,y,16,14,state,0);
495 x += 4 + (state?1:0);
496 y += 3 + (state?1:0);
497
498 line(dest, x+2, y+0, x+5, y+0, c);
499 line(dest, x+1, y+1, x+2, y+1, c);
500 line(dest, x+5, y+1, x+6, y+1, c);
501 line(dest, x+4, y+2, x+5, y+2, c);
502 line(dest, x+3, y+3, x+4, y+3, c);
503 line(dest, x+3, y+4, x+4, y+4, c);
504 line(dest, x+3, y+6, x+4, y+6, c);
505 line(dest, x+3, y+7, x+4, y+7, c);
506 }
507
508 void draw_x_button(BITMAP *dest, int32_t x, int32_t y, int32_t state)
509 {
510 int32_t c = scheme[jcBOXFG];
511
512 jwin_draw_button(dest,x,y,16,14,state,0);
513 x += 4 + (state?1:0);
514 y += 3 + (state?1:0);
515
516 line(dest,x, y, x+6,y+6,c);
517 line(dest,x+1,y, x+7,y+6,c);
518 line(dest,x, y+6,x+6,y, c);
519 line(dest,x+1,y+6,x+7,y, c);
520 }
521
522 void draw_arrow(BITMAP *dest, int c, int x, int y, int h, bool up, bool center)
523 {
524 if(!center)
525 x += h-1;
526 for(int i = 0; i<h; i++)
527 hline(dest, x-(up?i:h-i-1), y+i, x+(up?i:h-i-1), c);
528 }
529 void draw_arrow_horz(BITMAP *dest, int c, int x, int y, int w, bool left, bool center)
530 {
531 if(!center)
532 y += w-1;
533 for(int i = 0; i<w; i++)
534 vline(dest, x+i, y-(left?i:w-i-1), y+(left?i:w-i-1), c);
535 }
536 void draw_arrow_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, int32_t up, int32_t state)
537 {
538 int32_t c = scheme[jcDARK];
539 int32_t ah = zc_min(h/3, 5);
540 int32_t i = 0;
541
542 jwin_draw_button(dest,x,y,w,h,state,1);
543 x += w/2 - (state?0:1);
544 y += (h-ah)/2 + (state?1:0);
545
546 for(; i<ah; i++)
547 {
548 hline(dest, x-(up?i:ah-i-1), y+i, x+(up?i:ah-i-1), c);
549 }
550 }
551
552 void draw_arrow_button_horiz(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, int32_t up, int32_t state)
553 {
554 int32_t c = scheme[jcDARK];
555 int32_t aw = zc_min(w/3, 5);
556 int32_t i = 0;
557
558 jwin_draw_button(dest,x,y,w,h,state,1);
559 y += h/2 - (state?0:1);
560 x += (w-aw)/2 + (state?1:0);
561
562 for(; i<aw; i++)
563 {
564 vline(dest, x+i,y-(up?i:aw-i-1), y+(up?i:aw-i-1), c);
565 }
566 }
567
568 int32_t mouse_in_rect(int32_t x,int32_t y,int32_t w,int32_t h)
569 {
570 return ((gui_mouse_x() >= x) && (gui_mouse_y() >= y) &&
571 (gui_mouse_x() < x + w) && (gui_mouse_y() < y + h));
572 }
573
574 static int32_t jwin_do_x_button(BITMAP *dest, int32_t x, int32_t y)
575 {
576 int32_t down=0, last_draw = 0;
577
578 while(gui_mouse_b())
579 {
580 down = mouse_in_rect(x,y,16,14);
581
582 if(down!=last_draw)
583 {
584 draw_x_button(dest,x,y,down);
585 last_draw = down;
586 }
587
588 /* let other objects continue to animate */
589 broadcast_dialog_message(MSG_IDLE, 0);
590 rest(1);
591 }
592
593 if(down)
594 {
595 draw_x_button(dest,x,y,0);
596 }
597
598 return down;
599 }
600
601 /* dotted_rect:
602 * Draws a dotted rectangle, for showing an object has the input focus.
603 */
604 void dotted_rect(BITMAP *dest, int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t fg, int32_t bg)
605 {
606 int32_t x = ((x1+y1) & 1) ? 1 : 0;
607 int32_t c;
608
609 //acquire the bitmap ourselves, because locking a surface within each call is *SLOW AS BALLS* -DD
610 acquire_bitmap(dest);
611
612 for(c=x1; c<=x2; c++)
613 {
614 putpixel(dest, c, y1, (((c+y1) & 1) == x) ? fg : bg);
615 putpixel(dest, c, y2, (((c+y2) & 1) == x) ? fg : bg);
616 }
617
618 for(c=y1+1; c<y2; c++)
619 {
620 putpixel(dest, x1, c, (((c+x1) & 1) == x) ? fg : bg);
621 putpixel(dest, x2, c, (((c+x2) & 1) == x) ? fg : bg);
622 }
623
624 release_bitmap(dest);
625
626 }
627
628 static void _dotted_rect(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t fg, int32_t bg)
629 {
630 dotted_rect(screen, x1, y1, x2, y2, fg, bg);
631 }
632
633 static bool no_hline = false;
634 /* gui_textout_ln:
635 * Wrapper function for drawing text to the screen, which interprets the
636 * & character as an underbar for displaying keyboard shortcuts. Returns
637 * the width of the output string in pixels.
638 *
639 * Handles '\n' characters.
640 */
641 4 int32_t gui_textout_ln(BITMAP *bmp, FONT *f, unsigned const char *s, int32_t x, int32_t y, int32_t color, int32_t bg, int32_t pos)
642 {
643 char tmp[1024];
644 4 int32_t c = 0;
645 int32_t len;
646 4 int32_t pix_len = 0;
647 4 int32_t max_len = 0;
648 int32_t hline_pos;
649 4 int32_t xx = x;
650 4 bool is_scr = bmp == screen;
651
652
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 4 times.
14 while(s[c])
653 {
654 10 len = 0;
655 10 hline_pos = -1;
656
657
4/4
✓ Branch 0 taken 532 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 532 times.
536 for(; (s[c]) && (len<(int32_t)(sizeof(tmp)-1)); c++)
658 {
659
2/2
✓ Branch 0 taken 526 times.
✓ Branch 1 taken 6 times.
532 if(s[c] == '\n')
660 {
661 6 c++;
662 6 break;
663 }
664
2/4
✓ Branch 0 taken 526 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 526 times.
✗ Branch 3 not taken.
526 else if(!no_hline && s[c] == '&')
665 {
666 if(s[c+1] != '&')
667 hline_pos = len;
668 else
669 {
670 tmp[len++] = '&';
671 c++;
672 }
673 }
674 else
675 526 tmp[len++] = s[c];
676 526 }
677
678 10 tmp[len] = 0;
679 10 pix_len = text_length(f, tmp);
680
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8 times.
10 if (pix_len > max_len) max_len = pix_len;
681 10 x = xx;
682
683
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if(pos==1) //center
684 {
685 x -= pix_len / 2;
686 }
687
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 else if(pos==2) //right
688 {
689 x -= pix_len;
690 }
691
692
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if(bmp)
693 {
694 10 textout_ex(bmp, f, tmp, x, y, color,bg);
695
696
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if(hline_pos >= 0)
697 {
698 int32_t i;
699 i = tmp[hline_pos];
700 tmp[hline_pos] = 0;
701 hline_pos = text_length(f, tmp);
702 tmp[0] = i;
703 tmp[1] = 0;
704 i = text_length(f, tmp);
705 hline(bmp, x+hline_pos, y+text_height(f)-gui_font_baseline, x+hline_pos+i-1, color);
706 }
707 10 }
708
709 10 y += text_height(f);
710 }
711 4 return max_len;
712 }
713
714 4 int32_t gui_textout_ln(BITMAP *bmp, unsigned const char *s, int32_t x, int32_t y, int32_t color, int32_t bg, int32_t pos)
715 {
716 4 return gui_textout_ln(bmp, font, s, x, y, color, bg, pos);
717 }
718
719 int32_t gui_text_width(FONT *f, const char *s)
720 {
721 return gui_textout_ln(NULL, f, (uint8_t*)s, 0, 0, 0, 0, 0);
722 }
723
724 4 int32_t count_newline(uint8_t *s)
725 {
726 4 int32_t cnt = 0;
727
2/2
✓ Branch 0 taken 532 times.
✓ Branch 1 taken 4 times.
536 for(int32_t q = 0; s[q] != 0; ++q)
728 {
729
2/2
✓ Branch 0 taken 526 times.
✓ Branch 1 taken 6 times.
532 if(s[q] == '\n') ++cnt;
730 532 }
731 4 return cnt;
732 }
733
734 4 int32_t gui_textheight(FONT* f, uint8_t *s)
735 {
736 4 return text_height(f) * (count_newline(s) + 1);
737 }
738
739 4 int32_t gui_textheight(uint8_t* s)
740 {
741 4 return gui_textheight(font, s);
742 }
743
744 /* typedef for the listbox callback functions */
745 typedef char *(*getfuncptr)(int32_t, int32_t *);
746
747 /* event handler that closes a dialog */
748 int32_t close_dlg()
749 {
750 return D_CLOSE;
751 }
752
753 int32_t jwin_frame_proc(int32_t msg, DIALOG *d, int32_t c)
754 {
755 //these are here to bypass compiler warnings about unused arguments
756 c=c;
757
758 if(msg == MSG_DRAW)
759 {
760 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, d->d1);
761 }
762
763 return D_O_K;
764 }
765
766 int32_t jwin_guitest_proc(int32_t msg, DIALOG *d, int32_t c)
767 {
768 //these are here to bypass compiler warnings about unused arguments
769 c=c;
770
771 if(msg == MSG_DRAW)
772 {
773 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, d->d1);
774 }
775
776 return D_O_K;
777 }
778
779 /* jwin_win_proc:
780 * Draws a box with a frame. Use dp for a title string. If dp is NULL,
781 * it won't draw a title bar. If the D_EXIT flag is set, it will also
782 * draw an "X" button on the title bar that can be used to close the
783 * dialog.
784 * If d->dp3 is non-null, it will be read as a help text string, and
785 * a ? button will be drawn, that upon clicking will display the helptext.
786 */
787 int32_t jwin_win_proc(int32_t msg, DIALOG *d, int32_t c)
788 {
789 //these are here to bypass compiler warnings about unused arguments
790 c=c;
791
792 rest(1);
793 static bool skipredraw = false;
794
795 switch(msg)
796 {
797 case MSG_DRAW:
798 if(skipredraw)
799 {
800 skipredraw = false;
801 break;
802 }
803 jwin_draw_win(screen, d->x, d->y, d->w, d->h, FR_WIN);
804
805 if(d->dp)
806 {
807 FONT *oldfont = font;
808
809 if(d->dp2)
810 {
811 font = (FONT*)d->dp2;
812 }
813
814 jwin_draw_titlebar(screen, d->x+3, d->y+3, d->w-6, 18, (char*)d->dp, d->flags & D_EXIT, d->dp3!=NULL);
815 font = oldfont;
816 }
817 break;
818
819 case MSG_WANTFOCUS:
820 if(gui_mouse_b())
821 return D_WANTFOCUS|D_REDRAW;
822 else return D_O_K;
823 case MSG_GOTFOCUS:
824 case MSG_LOSTFOCUS:
825 skipredraw = true;
826 return D_O_K;
827
828 case MSG_CLICK:
829 {
830 if((d->flags & D_EXIT) && mouse_in_rect(d->x+d->w-21, d->y+5, 16, 14))
831 {
832 if(jwin_do_x_button(screen, d->x+d->w-21, d->y+5))
833 {
834 GUI_EVENT(d, geCLOSE);
835 return D_CLOSE;
836 }
837 }
838 if(char const* helpstr = (char const*)d->dp3)
839 {
840 if(mouse_in_rect(d->x+d->w-((d->flags&D_EXIT)?39:21), d->y+5, 16, 14))
841 {
842 broadcast_dialog_message(MSG_DRAW,0);
843 InfoDialog("Info", helpstr).show();
844 }
845 }
846 }
847 break;
848 }
849
850 return D_O_K;
851 }
852
853 /* jwin_text_proc:
854 * Simple dialog procedure: draws the text string which is pointed to by dp.
855 *
856 * Handles '\n' characters.
857 */
858 4 int32_t jwin_text_proc(int32_t msg, DIALOG *d, int32_t)
859 {
860 ASSERT(d);
861
3/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 static BITMAP *dummy=create_bitmap_ex(8, 1, 1);
862
863
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 switch(msg)
864 {
865 case MSG_START:
866 {
867 4 FONT *oldfont = font;
868
869
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if(d->dp2)
870 {
871 4 font = (FONT*)d->dp2;
872 4 }
873
874 4 d->w=gui_textout_ln(dummy, (uint8_t *)d->dp, 0, 0, scheme[jcMEDDARK], -1, 0);
875 4 d->h=gui_textheight((uint8_t *)d->dp);
876
877 4 font = oldfont;
878 4 break;
879 }
880 case MSG_DRAW:
881 {
882 FONT *oldfont = font;
883
884 if(d->dp2)
885 {
886 font = (FONT*)d->dp2;
887 }
888
889 if(d->flags & D_DISABLED)
890 {
891 gui_textout_ln(screen, (uint8_t*)d->dp, d->x+1, d->y+1, scheme[jcLIGHT], scheme[jcBOX], 0);
892 d->w=gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcDISABLED_FG], -1, 0);
893 }
894 else
895 {
896 d->w=gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcBOXFG], scheme[jcBOX], 0);
897 }
898
899 font = oldfont;
900 break;
901 }
902 }
903
904 4 return D_O_K;
905 }
906
907 int32_t jwin_ctext_proc(int32_t msg, DIALOG *d, int32_t)
908 {
909 ASSERT(d);
910 static BITMAP *dummy=create_bitmap_ex(8, 320, 240);
911
912 switch(msg)
913 {
914 case MSG_START:
915 d->w=gui_textout_ln(dummy, (uint8_t *)d->dp, 0, 0, scheme[jcMEDDARK], -1, 0);
916 break;
917
918 case MSG_DRAW:
919 FONT *oldfont = font;
920
921 if(d->dp2)
922 {
923 font = (FONT*)d->dp2;
924 }
925
926 if(d->flags & D_DISABLED)
927 {
928 gui_textout_ln(screen, (uint8_t*)d->dp, d->x+1, d->y+1, scheme[jcLIGHT], scheme[jcBOX], 1);
929 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcDISABLED_FG], -1, 1);
930 }
931 else
932 {
933 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcBOXFG], scheme[jcBOX], 1);
934 }
935
936 font = oldfont;
937 break;
938 }
939
940 return D_O_K;
941 }
942
943 int32_t jwin_rtext_proc(int32_t msg, DIALOG *d, int32_t)
944 {
945 ASSERT(d);
946 static BITMAP *dummy=create_bitmap_ex(8, 1, 1);
947
948 switch(msg)
949 {
950 case MSG_START:
951 d->w=gui_textout_ln(dummy, (uint8_t *)d->dp, 0, 0, scheme[jcMEDDARK], -1, 2);
952 break;
953
954 case MSG_DRAW:
955 FONT *oldfont = font;
956
957 if(d->dp2)
958 {
959 font = (FONT*)d->dp2;
960 }
961
962 if(d->flags & D_DISABLED)
963 {
964 gui_textout_ln(screen, (uint8_t*)d->dp, d->x+1, d->y+1, scheme[jcLIGHT], scheme[jcBOX], 2);
965 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcDISABLED_FG], -1, 2);
966 }
967 else
968 {
969 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcBOXFG], scheme[jcBOX], 2);
970 }
971
972 font = oldfont;
973 break;
974 }
975
976 return D_O_K;
977 }
978
979 int32_t d_ctext2_proc(int32_t msg, DIALOG *d, int32_t c)
980 {
981 auto ret = d_ctext_proc(msg, d, c);
982 return ret;
983 }
984
985 int32_t new_text_proc(int32_t msg, DIALOG *d, int32_t c)
986 {
987 BITMAP* oldscreen = screen;
988 if(msg==MSG_DRAW)
989 {
990 if(d->flags & D_HIDDEN) return D_O_K;
991 screen = create_bitmap_ex(8,oldscreen->w,oldscreen->h);
992 clear_bitmap(screen);
993 set_clip_rect(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1);
994 }
995 int32_t ret = D_O_K;
996 int32_t w = d->w, h = d->h, x = d->x, y = d->y;
997 if(d->d2) no_hline = true;
998 switch(d->d1)
999 {
1000 case 0:
1001 ret = jwin_text_proc(msg, d, c);
1002 break;
1003 case 1:
1004 d->x += d->w/2;
1005 ret = jwin_ctext_proc(msg, d, c);
1006 break;
1007 case 2:
1008 d->x += d->w - 1;
1009 ret = jwin_rtext_proc(msg, d, c);
1010 break;
1011 }
1012 no_hline = false;
1013 d->w = w;
1014 d->h = h;
1015 d->x = x;
1016 d->y = y;
1017 if(msg==MSG_DRAW)
1018 {
1019 masked_blit(screen, oldscreen, d->x, d->y, d->x, d->y, d->w, d->h);
1020 destroy_bitmap(screen);
1021 screen = oldscreen;
1022 }
1023 if(msg==MSG_WANTFOCUS && gui_mouse_b())
1024 ret |= D_WANTFOCUS|D_REDRAW;
1025 return ret;
1026 }
1027
1028 /* draw_text_button:
1029 * Helper for jwin_button_proc.
1030 */
1031 void jwin_draw_text_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, const char *str, int32_t flags, bool show_dotted_rect)
1032 {
1033 int32_t g = (flags & D_SELECTED) ? 1 : 0;
1034
1035 if(flags & D_SELECTED)
1036 {
1037 jwin_draw_button(dest, x, y, w, h, 2, 0);
1038 flags &= ~D_DISABLED;
1039 }
1040 else if(!(flags & D_GOTFOCUS))
1041 jwin_draw_button(dest, x, y, w, h, 0, 0);
1042 else
1043 {
1044 rect(dest, x, y, x+w-1, y+h-1, scheme[jcDARK]);
1045 jwin_draw_button(dest, x+1, y+1, w-2, h-2, 0, 0);
1046 }
1047
1048 bool drawstring = true;
1049 if(str[1]==0 && byte(str[0]) >= 0x80)
1050 {
1051 drawstring = false;
1052 int col = jwin_pal[(flags & D_DISABLED) ? jcLIGHT : jcBOXFG];
1053 int aw = w/4, ah = h/4;
1054 int woff = (aw/2)+1, hoff = (ah/2)+1;
1055 int x1 = x+w/2, x2 = x+(w-aw)/2;
1056 int y1 = y+(h-aw)/2, y2 = y+h/2;
1057 switch(byte(str[0]))
1058 {
1059 case 0x88:
1060 draw_arrow(dest, col, x1, y1, ah, true, true);
1061 break;
1062 case 0x89:
1063 draw_arrow(dest, col, x1, y1, ah, false, true);
1064 break;
1065 case 0x8A:
1066 draw_arrow_horz(dest, col, x2, y2, aw, true, true);
1067 break;
1068 case 0x8B:
1069 draw_arrow_horz(dest, col, x2, y2, aw, false, true);
1070 break;
1071 case 0x98:
1072 draw_arrow(dest, col, x1, y1-hoff, ah, false, true);
1073 draw_arrow(dest, col, x1, y1+hoff, ah, true, true);
1074 break;
1075 case 0x99:
1076 draw_arrow(dest, col, x1, y1-hoff, ah, true, true);
1077 draw_arrow(dest, col, x1, y1+hoff, ah, false, true);
1078 break;
1079 case 0x9A:
1080 draw_arrow_horz(dest, col, x2-woff, y2, aw, false, true);
1081 draw_arrow_horz(dest, col, x2+woff, y2, aw, true, true);
1082 break;
1083 case 0x9B:
1084 draw_arrow_horz(dest, col, x2-woff, y2, aw, true, true);
1085 draw_arrow_horz(dest, col, x2+woff, y2, aw, false, true);
1086 break;
1087 default: drawstring = true;
1088 }
1089 }
1090 if(drawstring)
1091 {
1092 if(!(flags & D_DISABLED))
1093 gui_textout_ex(dest, str, x+w/2+g, y+(h-text_height(font))/2+g, scheme[jcBOXFG], -1, TRUE);
1094 else
1095 {
1096 gui_textout_ex(dest, str, x+w/2+1,y+(h-text_height(font))/2+1, scheme[jcLIGHT], -1, TRUE);
1097 gui_textout_ex(dest, str, x+w/2, y+(h-text_height(font))/2, scheme[jcDISABLED_FG], -1, TRUE);
1098 }
1099 }
1100
1101 if(show_dotted_rect&&(flags & D_GOTFOCUS))
1102 dotted_rect(dest, x+4, y+4, x+w-5, y+h-5, scheme[jcDARK], scheme[jcBOX]);
1103 }
1104
1105 int icon_proportion(int icon,int s1,int s2)
1106 {
1107 int sz = round(sqrt(zc_min(s1,s2))*1.25);
1108 switch(icon)
1109 {
1110 case BTNICON_STOPSQUARE:
1111 sz += 4;
1112 break;
1113 case BTNICON_PLUS:
1114 case BTNICON_MINUS:
1115 sz += 4;
1116 break;
1117 }
1118 return sz;
1119 }
1120 void jwin_draw_icon_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, int icon, int32_t flags, bool show_dotted_rect)
1121 {
1122 int32_t g = (flags & D_SELECTED) ? 1 : 0;
1123
1124 if(flags & D_SELECTED)
1125 jwin_draw_button(dest, x, y, w, h, 2, 0);
1126 else if(!(flags & D_GOTFOCUS))
1127 jwin_draw_button(dest, x, y, w, h, 0, 0);
1128 else
1129 {
1130 rect(dest, x, y, x+w-1, y+h-1, scheme[jcDARK]);
1131 jwin_draw_button(dest, x+1, y+1, w-2, h-2, 0, 0);
1132 }
1133
1134 int col = jwin_pal[(flags & D_DISABLED) ? jcLIGHT : jcBOXFG];
1135 jwin_draw_icon(dest,x+w/2,y+h/2,col,icon,icon_proportion(icon,w,h),true);
1136
1137 if(show_dotted_rect&&(flags & D_GOTFOCUS))
1138 dotted_rect(dest, x+4, y+4, x+w-5, y+h-5, scheme[jcDARK], scheme[jcBOX]);
1139 }
1140 void jwin_draw_icon(BITMAP *dest, int x, int y, int col, int icon, int asz, bool center)
1141 {
1142 jwin_draw_icon(dest,x,y,col,icon,asz,asz,center);
1143 }
1144 void jwin_draw_icon(BITMAP *dest, int x, int y, int col, int icon, int aw, int ah, bool center)
1145 {
1146 int w2 = aw, h2 = ah;
1147 int sz = zc_min(aw,ah);
1148 switch(icon)
1149 {
1150 case BTNICON_ARROW_LEFT2:
1151 case BTNICON_ARROW_RIGHT2:
1152 aw *= 2;
1153 ah = aw*2-1;
1154 break;
1155 case BTNICON_ARROW_LEFT3:
1156 case BTNICON_ARROW_RIGHT3:
1157 aw *= 3;
1158 ah = aw*2-1;
1159 break;
1160 case BTNICON_ARROW_UP:
1161 case BTNICON_ARROW_DOWN:
1162 case BTNICON_CONTRACT_VERT:
1163 case BTNICON_EXPAND_VERT:
1164 aw = ah*2-1;
1165 break;
1166 case BTNICON_ARROW_LEFT:
1167 case BTNICON_ARROW_RIGHT:
1168 case BTNICON_CONTRACT_HORZ:
1169 case BTNICON_EXPAND_HORZ:
1170 ah = aw*2-1;
1171 break;
1172 case BTNICON_STOPSQUARE:
1173 aw = ah = sz;
1174 break;
1175 case BTNICON_PLUS:
1176 if(!(sz%2)) ++sz;
1177 aw = ah = w2 = h2 = sz;
1178 w2 /= 3;
1179 h2 /= 3;
1180 if(!(h2%2)) ++h2;
1181 if(!(w2%2)) ++w2;
1182 break;
1183 case BTNICON_MINUS:
1184 if(!(sz%2)) ++sz;
1185 aw = ah = w2 = h2 = sz;
1186 h2 /= 3;
1187 if(!(h2%2)) ++h2;
1188 break;
1189 }
1190 int woff = (aw/2)+1, hoff = (ah/2)+1;
1191 int cx = center ? (x-aw/2) : x,
1192 cy = center ? (y-ah/2) : y;
1193 switch(icon)
1194 {
1195 case BTNICON_ARROW_UP:
1196 draw_arrow(dest, col, x, cy, ah, true, center);
1197 break;
1198 case BTNICON_ARROW_DOWN:
1199 draw_arrow(dest, col, x, cy, ah, false, center);
1200 break;
1201 case BTNICON_ARROW_LEFT:
1202 draw_arrow_horz(dest, col, cx, y, aw, true, center);
1203 break;
1204 case BTNICON_ARROW_RIGHT:
1205 draw_arrow_horz(dest, col, cx, y, aw, false, center);
1206 break;
1207 case BTNICON_CONTRACT_VERT:
1208 draw_arrow(dest, col, x, cy-hoff, ah, false, center);
1209 draw_arrow(dest, col, x, cy+hoff, ah, true, center);
1210 break;
1211 case BTNICON_EXPAND_VERT:
1212 draw_arrow(dest, col, x, cy-hoff, ah, true, center);
1213 draw_arrow(dest, col, x, cy+hoff, ah, false, center);
1214 break;
1215 case BTNICON_CONTRACT_HORZ:
1216 draw_arrow_horz(dest, col, cx-woff, y, aw, false, center);
1217 draw_arrow_horz(dest, col, cx+woff, y, aw, true, center);
1218 break;
1219 case BTNICON_EXPAND_HORZ:
1220 draw_arrow_horz(dest, col, cx-woff, y, aw, true, center);
1221 draw_arrow_horz(dest, col, cx+woff, y, aw, false, center);
1222 break;
1223 case BTNICON_ARROW_LEFT2:
1224 draw_arrow_horz(dest, col, cx, y, w2, true, center);
1225 draw_arrow_horz(dest, col, cx+w2, y, w2, true, center);
1226 break;
1227 case BTNICON_ARROW_LEFT3:
1228 draw_arrow_horz(dest, col, cx, y, w2, true, center);
1229 draw_arrow_horz(dest, col, cx+w2, y, w2, true, center);
1230 draw_arrow_horz(dest, col, cx+w2*2, y, w2, true, center);
1231 break;
1232 case BTNICON_ARROW_RIGHT2:
1233 draw_arrow_horz(dest, col, cx, y, w2, false, center);
1234 draw_arrow_horz(dest, col, cx+w2, y, w2, false, center);
1235 break;
1236 case BTNICON_ARROW_RIGHT3:
1237 draw_arrow_horz(dest, col, cx, y, w2, false, center);
1238 draw_arrow_horz(dest, col, cx+w2, y, w2, false, center);
1239 draw_arrow_horz(dest, col, cx+w2*2, y, w2, false, center);
1240 break;
1241 case BTNICON_STOPSQUARE:
1242 rectfill(dest, cx, cy, cx+aw-1, cy+ah-1, col);
1243 break;
1244 case BTNICON_MINUS:
1245 rectfill(dest, cx, cy+(ah/2)-(h2/2), cx+aw-1, cy+(ah/2)+(h2/2), col);
1246 break;
1247 case BTNICON_PLUS:
1248 rectfill(dest, cx, cy+(ah/2)-(h2/2), cx+aw-1, cy+(ah/2)+(h2/2), col);
1249 rectfill(dest, cx+(aw/2)-(w2/2), cy, cx+(aw/2)+(w2/2), cy+ah-1, col);
1250 break;
1251 }
1252 }
1253 /* draw_graphics_button:
1254 * Helper for jwin_button_proc.
1255 */
1256 void jwin_draw_graphics_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, BITMAP *bmp, BITMAP *bmp2, int32_t flags, bool show_dotted_rect, bool overlay)
1257 {
1258 int32_t g = (flags & D_SELECTED) ? 1 : 0;
1259
1260 if(flags & D_SELECTED)
1261 jwin_draw_button(dest, x, y, w, h, 2, 0);
1262 else if(!(flags & D_GOTFOCUS))
1263 jwin_draw_button(dest, x, y, w, h, 0, 0);
1264 else
1265 {
1266 rect(dest, x, y, x+w-1, y+h-1, scheme[jcDARK]);
1267 jwin_draw_button(dest, x+1, y+1, w-2, h-2, 0, 0);
1268 }
1269
1270 if(!(flags & D_DISABLED))
1271 {
1272 // gui_textout_ex(dest, str, x+w/2+g, y+h/2-text_height(font)/2+g, scheme[jcBOXFG], -1, TRUE);
1273 if(bmp!=NULL)
1274 {
1275 if(overlay)
1276 {
1277 masked_blit(bmp, dest, 0, 0, x+w/2-bmp->w/2+g, y+h/2-bmp->h/2+g, bmp->h, bmp->w);
1278 }
1279 else
1280 {
1281 blit(bmp, dest, 0, 0, x+w/2-bmp->w/2+g, y+h/2-bmp->h/2+g, bmp->h, bmp->w);
1282 }
1283 }
1284 }
1285 else
1286 {
1287 // gui_textout_ex(dest, str, x+w/2+1,y+h/2-text_height(font)/2+1, scheme[jcLIGHT], -1, TRUE);
1288 // gui_textout_ex(dest, str, x+w/2, y+h/2-text_height(font)/2, scheme[jcMEDDARK], -1, TRUE);
1289 if(bmp2!=NULL)
1290 {
1291 if(overlay)
1292 {
1293 masked_blit(bmp2, dest, 0, 0, x+w/2-bmp2->w/2+g, y+h/2-bmp2->h/2+g, bmp2->h, bmp2->w);
1294 }
1295 else
1296 {
1297 blit(bmp2, dest, 0, 0, x+w/2-bmp2->w/2+g, y+h/2-bmp2->h/2+g, bmp2->h, bmp2->w);
1298 }
1299 }
1300 }
1301
1302 if(show_dotted_rect&&(flags & D_GOTFOCUS))
1303 dotted_rect(dest, x+4, y+4, x+w-5, y+h-5, scheme[jcDARK], scheme[jcBOX]);
1304 }
1305
1306 /* jwin_button_proc:
1307 * A button object (the dp field points to the text string). This object
1308 * can be selected by clicking on it with the mouse or by pressing its
1309 * keyboard shortcut. If the D_EXIT flag is set, selecting it will close
1310 * the dialog, otherwise it will toggle on and off.
1311 */
1312 int32_t jwin_button_proc(int32_t msg, DIALOG *d, int32_t)
1313 {
1314 int32_t down=0;
1315 int32_t selected=(d->flags&D_SELECTED)?1:0;
1316 int32_t disabled=(d->flags&D_DISABLED)?1:0;
1317 int32_t last_draw;
1318
1319 switch(msg)
1320 {
1321 case MSG_DRAW:
1322 {
1323 FONT *oldfont = font;
1324
1325 if(d->dp2)
1326 {
1327 font = (FONT*)d->dp2;
1328 }
1329
1330 jwin_draw_text_button(screen, d->x, d->y, d->w, d->h, (char*)d->dp, d->flags, true);
1331 font = oldfont;
1332 }
1333 break;
1334
1335 case MSG_WANTFOCUS:
1336 return D_WANTFOCUS;
1337
1338 case MSG_KEY:
1339 if(disabled) break;
1340 /* close dialog? */
1341 if(d->flags & D_EXIT)
1342 {
1343 return D_CLOSE;
1344 }
1345 if(d->d2 == 1) //Insta-button
1346 {
1347 GUI_EVENT(d, geCLICK);
1348 break;
1349 }
1350 /* or just toggle */
1351 d->flags ^= D_SELECTED;
1352 GUI_EVENT(d, geCLICK);
1353 object_message(d, MSG_DRAW, 0);
1354 break;
1355
1356 case MSG_CLICK:
1357 {
1358 if(disabled) break;
1359 if(d->d2 == 1) //Insta-button
1360 {
1361 if(mouse_in_rect(d->x, d->y, d->w, d->h))
1362 {
1363 GUI_EVENT(d, geCLICK);
1364 if(d->flags & D_EXIT)
1365 return D_CLOSE;
1366 }
1367 }
1368 else
1369 {
1370 last_draw = 0;
1371
1372 /* track the mouse until it is released */
1373 while(gui_mouse_b())
1374 {
1375 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1376
1377 /* redraw? */
1378 bool should_redraw = false;
1379 if(last_draw != down)
1380 {
1381 if(down != selected)
1382 d->flags |= D_SELECTED;
1383 else
1384 d->flags &= ~D_SELECTED;
1385
1386 object_message(d, MSG_DRAW, 0);
1387 last_draw = down;
1388 should_redraw = true;
1389 }
1390
1391 /* let other objects continue to animate */
1392 int r = broadcast_dialog_message(MSG_IDLE, 0);
1393 if (r & D_REDRAWME) should_redraw = true;
1394
1395 if (should_redraw)
1396 {
1397 update_hw_screen();
1398 }
1399 }
1400
1401 /* redraw in normal state */
1402 if(down)
1403 {
1404 GUI_EVENT(d, geCLICK);
1405 if(d->flags&D_EXIT)
1406 {
1407 d->flags &= ~D_SELECTED;
1408 object_message(d, MSG_DRAW, 0);
1409 }
1410 }
1411
1412 /* should we close the dialog? */
1413 if(down && (d->flags & D_EXIT))
1414 return D_CLOSE;
1415 }
1416 }
1417 break;
1418 }
1419 return D_O_K;
1420 }
1421 int32_t jwin_iconbutton_proc(int32_t msg, DIALOG *d, int32_t)
1422 {
1423 int32_t down=0;
1424 int32_t selected=(d->flags&D_SELECTED)?1:0;
1425 int32_t last_draw;
1426
1427 switch(msg)
1428 {
1429 case MSG_DRAW:
1430 {
1431 jwin_draw_icon_button(screen, d->x, d->y, d->w, d->h, d->d1, d->flags, true);
1432 }
1433 break;
1434
1435 case MSG_WANTFOCUS:
1436 return D_WANTFOCUS;
1437
1438 case MSG_KEY:
1439 /* close dialog? */
1440 if(d->flags & D_EXIT)
1441 {
1442 return D_CLOSE;
1443 }
1444 if(d->d2 == 1) //Insta-button
1445 {
1446 GUI_EVENT(d, geCLICK);
1447 break;
1448 }
1449 /* or just toggle */
1450 d->flags ^= D_SELECTED;
1451 GUI_EVENT(d, geCLICK);
1452 object_message(d, MSG_DRAW, 0);
1453 break;
1454
1455 case MSG_CLICK:
1456 {
1457 if(d->d2 == 1) //Insta-button
1458 {
1459 if(mouse_in_rect(d->x, d->y, d->w, d->h))
1460 {
1461 GUI_EVENT(d, geCLICK);
1462 if(d->flags & D_EXIT)
1463 return D_CLOSE;
1464 }
1465 }
1466 else
1467 {
1468 last_draw = 0;
1469
1470 /* track the mouse until it is released */
1471 while(gui_mouse_b())
1472 {
1473 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1474
1475 /* redraw? */
1476 bool should_redraw = false;
1477 if(last_draw != down)
1478 {
1479 if(down != selected)
1480 d->flags |= D_SELECTED;
1481 else
1482 d->flags &= ~D_SELECTED;
1483
1484 object_message(d, MSG_DRAW, 0);
1485 last_draw = down;
1486 should_redraw = true;
1487 }
1488
1489 /* let other objects continue to animate */
1490 int r = broadcast_dialog_message(MSG_IDLE, 0);
1491 if (r & D_REDRAWME) should_redraw = true;
1492
1493 if (should_redraw)
1494 {
1495 update_hw_screen();
1496 }
1497 }
1498
1499 /* redraw in normal state */
1500 if(down)
1501 {
1502 GUI_EVENT(d, geCLICK);
1503 if(d->flags&D_EXIT)
1504 {
1505 d->flags &= ~D_SELECTED;
1506 object_message(d, MSG_DRAW, 0);
1507 }
1508 }
1509
1510 /* should we close the dialog? */
1511 if(down && (d->flags & D_EXIT))
1512 return D_CLOSE;
1513 }
1514 }
1515 break;
1516 }
1517 return D_O_K;
1518 }
1519 int32_t jwin_infobtn_proc(int32_t msg, DIALOG *d, int32_t)
1520 {
1521 int32_t down=0;
1522 int32_t selected=(d->flags&D_SELECTED)?1:0;
1523 int32_t last_draw;
1524 std::string* str = (std::string*)d->dp;
1525 bool dis = (d->flags & D_DISABLED) || !str || !((*str)[0]) || str->find_first_not_of(" \t")==std::string::npos;
1526 int flags = d->flags | (dis?D_DISABLED:0);
1527 bool show = false;
1528 switch(msg)
1529 {
1530 case MSG_DRAW:
1531 {
1532 FONT *oldfont = font;
1533
1534 if(d->dp2)
1535 font = (FONT*)d->dp2;
1536
1537 jwin_draw_text_button(screen, d->x, d->y, d->w, d->h, "?", flags, true);
1538 font = oldfont;
1539 }
1540 break;
1541
1542 case MSG_WANTFOCUS:
1543 if(dis) break;
1544 return D_WANTFOCUS;
1545
1546 case MSG_KEY:
1547 if(dis) break;
1548 show = true;
1549 break;
1550
1551 case MSG_CLICK:
1552 {
1553 if(dis) break;
1554 if(d->d2 == 1) //Insta-button
1555 {
1556 if(mouse_in_rect(d->x, d->y, d->w, d->h))
1557 {
1558 show = true;
1559 break;
1560 }
1561 }
1562 else
1563 {
1564 last_draw = 0;
1565
1566 /* track the mouse until it is released */
1567 while(gui_mouse_b())
1568 {
1569 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1570
1571 /* redraw? */
1572 bool should_redraw = false;
1573 if(last_draw != down)
1574 {
1575 if(down != selected)
1576 d->flags |= D_SELECTED;
1577 else
1578 d->flags &= ~D_SELECTED;
1579
1580 object_message(d, MSG_DRAW, 0);
1581 last_draw = down;
1582 should_redraw = true;
1583 }
1584
1585 /* let other objects continue to animate */
1586 int r = broadcast_dialog_message(MSG_IDLE, 0);
1587 if (r & D_REDRAWME) should_redraw = true;
1588
1589 if (should_redraw)
1590 {
1591 update_hw_screen();
1592 }
1593 }
1594
1595 /* redraw in normal state */
1596 if(down)
1597 show = true;
1598 }
1599 }
1600 break;
1601 }
1602 if(show)
1603 {
1604 d->flags &= ~D_SELECTED;
1605 object_message(d, MSG_DRAW, 0);
1606 InfoDialog("Info",*str).show();
1607 GUI_EVENT(d, geCLICK);
1608 }
1609 return D_O_K;
1610 }
1611
1612 /* jwin_func_button_proc:
1613 * A button that runs a void() function when clicked.
1614 * dp: Button text
1615 * dp2: Function to run
1616 */
1617 int32_t jwin_func_button_proc(int32_t msg, DIALOG *d, int32_t c)
1618 {
1619 int32_t down=0;
1620 int32_t selected=(d->flags&D_SELECTED)?1:0;
1621 int32_t last_draw;
1622
1623 if(msg==MSG_CLICK || msg==MSG_KEY)
1624 {
1625 last_draw = 0;
1626
1627 /* track the mouse until it is released */
1628 while(gui_mouse_b())
1629 {
1630 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1631
1632 /* redraw? */
1633 bool should_redraw = false;
1634 if(last_draw != down)
1635 {
1636 if(down != selected)
1637 d->flags |= D_SELECTED;
1638 else
1639 d->flags &= ~D_SELECTED;
1640
1641 object_message(d, MSG_DRAW, 0);
1642 last_draw = down;
1643 should_redraw = true;
1644 }
1645
1646 /* let other objects continue to animate */
1647 int r = broadcast_dialog_message(MSG_IDLE, 0);
1648 if (r & D_REDRAWME) should_redraw = true;
1649
1650 if (should_redraw)
1651 {
1652 update_hw_screen();
1653 }
1654 }
1655
1656 /* redraw in normal state */
1657 if(down)
1658 {
1659 if(d->flags&D_EXIT)
1660 {
1661 d->flags &= ~D_SELECTED;
1662 object_message(d, MSG_DRAW, 0);
1663 }
1664 }
1665
1666 /* pop up and call the function */
1667 if(down)
1668 {
1669 d->flags &= ~D_SELECTED;
1670 object_message(d, MSG_DRAW, 0);
1671 typedef void (*funcType)(void);
1672 funcType func=reinterpret_cast<funcType>(d->dp3);
1673 func();
1674 }
1675
1676 return D_O_K;
1677 }
1678
1679 return jwin_button_proc(msg, d, c);
1680 }
1681
1682 /*(int32_t x = atoi(d->dp);
1683 if ( x > 256 )
1684 d->dp = (char*)"255";
1685 elseif (x < 0 ) d->dp = (char*)"0";
1686 */
1687
1688 #ifdef ALLEGRO_MACOSX
1689 static int WORD_FLAG = KB_ALT_FLAG;
1690 static int LINE_FLAG = KB_COMMAND_FLAG;
1691 #else
1692 static int WORD_FLAG = KB_CTRL_FLAG;
1693 static int LINE_FLAG = KB_ALT_FLAG;
1694 #endif
1695
1696 static int classify_char(char c)
1697 {
1698 if (c == ' ' || c == '\t' || c == '\r')
1699 return 0;
1700 if (c == '/')
1701 return 1;
1702 return 2;
1703 }
1704
1705 static void delete_word(char* s, int* cursor)
1706 {
1707 int start = *cursor;
1708 if (start == 0) return;
1709
1710 int i = start - 1;
1711 int first_ch_class = classify_char(s[i]);
1712 while (i >= 0 && s[i])
1713 {
1714 if (classify_char(s[i]) != first_ch_class)
1715 break;
1716 i--;
1717 }
1718
1719 i++;
1720 *cursor = i;
1721
1722 int j = start;
1723 while (s[j])
1724 s[i++] = s[j++];
1725 s[i] = 0;
1726 }
1727
1728 static void delete_line(char* s, int* cursor)
1729 {
1730 int start = *cursor;
1731 if (start == 0) return;
1732
1733 int i = start - 1;
1734 while (i >= 0 && s[i])
1735 {
1736 bool is_newline = s[i] == '\n';
1737 if (is_newline) break;
1738 i--;
1739 }
1740
1741 i++;
1742 *cursor = i;
1743
1744 int j = start;
1745 while (s[j])
1746 s[i++] = s[j++];
1747 s[i] = 0;
1748 }
1749
1750 int32_t jwin_vedit_proc(int32_t msg, DIALOG *d, int32_t c)
1751 {
1752 if(d->flags & D_HIDDEN)
1753 {
1754 switch(msg)
1755 {
1756 case MSG_CHAR: case MSG_UCHAR: case MSG_XCHAR: case MSG_DRAW: case MSG_CLICK: case MSG_DCLICK: case MSG_KEY: case MSG_WANTFOCUS:
1757 return D_O_K;
1758 }
1759 }
1760 if(d->h < 2+((text_height(d->dp2 ? (FONT*)d->dp2 : font)+2)*2))
1761 return jwin_edit_proc(msg, d, c);
1762 static char nullbuf[2];
1763 sprintf(nullbuf, " ");
1764 int32_t f, l, p, w, x, y, fg, bg;
1765 int32_t lastSpace = -1;
1766 char *s;
1767 char buf[2] = {0,0};
1768
1769 if(d->dp==NULL)
1770 {
1771 d->dp=(void *)nullbuf;
1772 }
1773
1774 s = (char*)d->dp;
1775 l = (int32_t)strlen(s);
1776
1777 int32_t cursor_start = d->d2 & 0x0000FFFF;
1778 int32_t cursor_end = int32_t((d->d2 & 0xFFFF0000) >> 16);
1779 // This was previously doing bitshifts on -1. There wasn't enough space so I cannibalized 0xFFFF instead. -Moosh
1780 if (cursor_start == 0xFFFF)
1781 cursor_start = -1;
1782 if (cursor_end == 0xFFFF)
1783 cursor_end = -1;
1784
1785 if(cursor_start > l)
1786 cursor_start = l;
1787 if(cursor_end > l)
1788 cursor_end = l;
1789 auto low_cursor = cursor_start<0 ? cursor_end : (cursor_end<0 ? cursor_start : (zc_min(cursor_start, cursor_end)));
1790 auto high_cursor = zc_max(cursor_start,cursor_end);
1791 bool range_selected = cursor_end > -1;
1792
1793 FONT *oldfont = font;
1794 if(d->dp2)
1795 font = (FONT*)d->dp2;
1796
1797 auto* char_length = font->vtable->char_length;
1798 std::vector<size_t> lines;
1799 x = 0;
1800
1801 y = d->y + 2;
1802 size_t ind = 0;
1803 int32_t yinc = text_height(font)+2;
1804 int32_t maxy = y;
1805 size_t maxlines = 1;
1806 while(maxy+yinc < d->y+d->h-3)
1807 {
1808 maxy += yinc;
1809 ++maxlines;
1810 }
1811 size_t half_width = (maxlines-1)/2;
1812 size_t line_scroll = 0;
1813 size_t focused_line = size_t(-1);
1814 size_t focused_line2 = size_t(-1);
1815 switch(msg)
1816 {
1817 //Only these messages need these calculations, so save processing.
1818 case MSG_DRAW:
1819 case MSG_CLICK:
1820 case MSG_CHAR:
1821 {
1822 for(auto q = 0; q <= l; ++q)
1823 {
1824 char c = s[q] ? s[q] : ' ';
1825 x += char_length(font, c);
1826 if(x > d->w - 6)
1827 {
1828 // Line's too long, break
1829 if(lastSpace >= 0)
1830 {
1831 q = lastSpace+1;
1832 lines.push_back(q);
1833 lastSpace = -1;
1834 }
1835 else
1836 {
1837 lines.push_back(q);
1838 }
1839 x = 0;
1840 --q; //counteract increment
1841 }
1842 else if(c == ' ')
1843 lastSpace = q;
1844 }
1845 if(lines.empty() || lines.back() != l+1)
1846 lines.push_back(l+1);
1847 for(size_t line = 0; line < lines.size(); ++line)
1848 {
1849 if(size_t(range_selected ? cursor_end : cursor_start) < lines[line]) //should ALWAYS execute once
1850 {
1851 focused_line = line;
1852 break;
1853 }
1854 }
1855 if(!range_selected)
1856 {
1857 focused_line2 = -1;
1858 }
1859 else for(size_t line = 0; line < lines.size(); ++line)
1860 {
1861 if(size_t(cursor_start) < lines[line]) //should ALWAYS execute once
1862 {
1863 focused_line2 = line;
1864 break;
1865 }
1866 }
1867 if (focused_line >= lines.size())
1868 focused_line = lines.size() - 1;
1869 if (focused_line2 >= lines.size())
1870 focused_line2 = lines.size() - 1;
1871 if(maxlines >= lines.size() || focused_line <= half_width)
1872 line_scroll = 0;
1873 else if(lines.size()-maxlines+half_width < focused_line)
1874 line_scroll = lines.size()-maxlines+half_width-1;
1875 else
1876 line_scroll = focused_line - half_width;
1877 }
1878 }
1879 font = oldfont; //in case of early return, need to reset here
1880 static bool dclick = false;
1881 switch(msg)
1882 {
1883 case MSG_START:
1884 dclick = false;
1885 cursor_start = (int32_t)strlen((char*)d->dp);
1886 cursor_end = -1;
1887 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
1888 break;
1889
1890 case MSG_DRAW:
1891 {
1892 if(d->dp2)
1893 font = (FONT*)d->dp2;
1894 if(d->flags & D_DISABLED)
1895 {
1896 fg = scheme[jcDISABLED_FG];
1897 bg = scheme[jcDISABLED_BG];
1898 }
1899 else if(d->flags & D_READONLY)
1900 {
1901 fg = scheme[jcALT_TEXTFG];
1902 bg = scheme[jcALT_TEXTBG];
1903 }
1904 else
1905 {
1906 fg = scheme[jcTEXTFG];
1907 bg = scheme[jcTEXTBG];
1908 }
1909
1910 //Fill the BG
1911 rectfill(screen, d->x+2, d->y+2, d->x+d->w-3, d->y+d->h-3, bg);
1912
1913 //Now the text
1914 size_t m = zc_min(line_scroll + maxlines, lines.size());
1915 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DEEP);
1916 for(size_t line = line_scroll; line < m; ++line, y+=yinc)
1917 {
1918 x = 3;
1919 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
1920 {
1921 char c = s[ind] ? s[ind] : ' ';
1922 w = char_length(font, c);
1923 bool focused = range_selected
1924 ? (ind >= low_cursor && ind <= high_cursor)
1925 : (ind == cursor_start);
1926 f = (focused && (d->flags & D_GOTFOCUS));
1927 buf[0] = c;
1928 textout_ex(screen, font, buf, d->x+x, y, f ? bg : fg,f ? fg : bg);
1929 x += w;
1930 }
1931 }
1932
1933 font = oldfont;
1934 break;
1935 }
1936
1937 case MSG_DCLICK:
1938 if ((gui_mouse_b() & 2) != 0)
1939 break;
1940 if (d->flags & (D_DISABLED | D_READONLY))
1941 break;
1942 dclick = true;
1943 break;
1944 case MSG_CLICK:
1945 {
1946 if(d->flags & (D_DISABLED|D_READONLY))
1947 break;
1948 if(d->dp2)
1949 font = (FONT*)d->dp2;
1950
1951 bool found = false;
1952 for(size_t line = line_scroll; line < lines.size() && line < (line_scroll + maxlines); ++line, y+=yinc)
1953 {
1954 if(gui_mouse_y() >= y+yinc)
1955 continue;
1956 x = d->x+3;
1957 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
1958 {
1959 x += char_length(font, s[ind]);
1960 if(x >= gui_mouse_x())
1961 {
1962 if(key_shifts&KB_SHIFT_FLAG)
1963 cursor_end = ind;
1964 else
1965 {
1966 cursor_start = ind;
1967 cursor_end = -1;
1968 if (dclick)
1969 cursor_end = cursor_start;
1970 }
1971 found = true;
1972 break;
1973 }
1974 }
1975 break;
1976 }
1977 if(!found)
1978 {
1979 if(key_shifts&KB_SHIFT_FLAG)
1980 cursor_end = l;
1981 else
1982 {
1983 cursor_start = l;
1984 cursor_end = -1;
1985 if (dclick)
1986 cursor_end = cursor_start;
1987 }
1988 }
1989
1990 if (dclick)
1991 {
1992 while (cursor_start > 0 && cursor_start < l)
1993 {
1994 if (s[cursor_start] == ' ')
1995 {
1996 if (cursor_start <= cursor_end)
1997 ++cursor_start;
1998 else
1999 --cursor_start;
2000 break;
2001 }
2002 if (cursor_start <= cursor_end)
2003 --cursor_start;
2004 else
2005 ++cursor_start;
2006 }
2007 while (cursor_end > 0 && cursor_end < l)
2008 {
2009 if (s[cursor_end] == ' ')
2010 {
2011 if (cursor_end >= cursor_start)
2012 --cursor_end;
2013 else
2014 ++cursor_end;
2015 break;
2016 }
2017 if (cursor_end >= cursor_start)
2018 ++cursor_end;
2019 else
2020 --cursor_end;
2021 }
2022 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2023 d->flags |= D_DIRTY;
2024 }
2025 else
2026 {
2027 if (cursor_end == cursor_start) cursor_end = -1;
2028 else d->flags |= D_DIRTY;
2029 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2030 }
2031
2032 object_message(d, MSG_DRAW, 0);
2033 font = oldfont;
2034 dclick = false;
2035 break;
2036 }
2037
2038 case MSG_WANTFOCUS:
2039 case MSG_LOSTFOCUS:
2040 case MSG_KEY:
2041 if(d->flags & (D_DISABLED|D_READONLY))
2042 break;
2043 return D_WANTFOCUS;
2044
2045 case MSG_CHAR:
2046 {
2047 if(d->flags & (D_DISABLED|D_READONLY))
2048 break;
2049 bool shifted = key_shifts & KB_SHIFT_FLAG;
2050 bool ctrl = key_shifts & KB_CTRL_FLAG;
2051 bool word_modifier = key_shifts & WORD_FLAG;
2052 bool line_modifier = key_shifts & LINE_FLAG;
2053 bool change_cursor = true;
2054 int32_t scursor = cursor_start, ecursor = cursor_end;
2055 char upper_c = c>>8;
2056 char lower_c = c&255;
2057
2058 if(shifted)
2059 {
2060 if(ecursor < 0)
2061 {
2062 ecursor = scursor;
2063 focused_line2 = focused_line;
2064 }
2065 }
2066 if(upper_c == KEY_LEFT)
2067 {
2068 if(shifted)
2069 {
2070 if(ecursor>0)
2071 --ecursor;
2072 }
2073 else
2074 {
2075 ecursor = -1;
2076 if(scursor > 0)
2077 --scursor;
2078 }
2079 }
2080 else if(upper_c == KEY_RIGHT)
2081 {
2082 if(shifted)
2083 {
2084 if(ecursor < l)
2085 ++ecursor;
2086 }
2087 else
2088 {
2089 ecursor = -1;
2090 if(scursor < l)
2091 ++scursor;
2092 }
2093 }
2094 else if(upper_c == KEY_UP || upper_c == KEY_DOWN)
2095 {
2096 if(shifted)
2097 {
2098 size_t line = focused_line2 + (upper_c == KEY_UP ? -1 : 1);
2099 if(!focused_line2 && upper_c == KEY_UP)
2100 ecursor = 0;
2101 else if(line >= lines.size())
2102 ecursor = l;
2103 else
2104 {
2105 if(d->dp2)
2106 font = (FONT*)d->dp2;
2107 x = d->x + 3;
2108 for(ind = focused_line2 ? lines[focused_line2-1] : 0; ind < lines[focused_line2]; ++ind)
2109 {
2110 w = char_length(font, s[ind]);
2111 if(ind < size_t(ecursor))
2112 x += w;
2113 else
2114 {
2115 x += w / 2;
2116 break;
2117 }
2118 }
2119
2120 int32_t tx = d->x+3;
2121 bool done = false;
2122 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
2123 {
2124 tx += char_length(font, s[ind] ? s[ind] : ' ');
2125 if(tx < x)
2126 continue;
2127 ecursor = ind;
2128 done = true;
2129 break;
2130 }
2131 font = oldfont;
2132 if(!done)
2133 {
2134 ecursor = (upper_c == KEY_UP) ? 0 : lines[line]-1;
2135 }
2136 }
2137 }
2138 else
2139 {
2140 ecursor = -1;
2141 if(range_selected)
2142 {
2143 focused_line = focused_line2;
2144 scursor = ecursor;
2145 }
2146 size_t line = focused_line + (upper_c == KEY_UP ? -1 : 1);
2147 if(!focused_line && upper_c == KEY_UP)
2148 scursor = 0;
2149 else if(line >= lines.size())
2150 scursor = l;
2151 else
2152 {
2153 if(d->dp2)
2154 font = (FONT*)d->dp2;
2155 x = d->x + 3;
2156 for(ind = focused_line ? lines[focused_line-1] : 0; ind < lines[focused_line]; ++ind)
2157 {
2158 w = char_length(font, s[ind]);
2159 if(ind < size_t(scursor))
2160 x += w;
2161 else
2162 {
2163 x += w / 2;
2164 break;
2165 }
2166 }
2167
2168 int32_t tx = d->x+3;
2169 bool done = false;
2170 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
2171 {
2172 tx += char_length(font, s[ind] ? s[ind] : ' ');
2173 if(tx < x)
2174 continue;
2175 scursor = ind;
2176 done = true;
2177 break;
2178 }
2179 font = oldfont;
2180 if(!done)
2181 {
2182 scursor = (upper_c == KEY_UP) ? 0 : lines[line]-1;
2183 }
2184 }
2185 }
2186 }
2187 else if(upper_c == KEY_HOME)
2188 {
2189 if(shifted)
2190 ecursor = 0;
2191 else
2192 {
2193 ecursor = -1;
2194 scursor = 0;
2195 }
2196 }
2197 else if(upper_c == KEY_END)
2198 {
2199 if(shifted)
2200 ecursor = l;
2201 else
2202 {
2203 ecursor = -1;
2204 scursor = l;
2205 }
2206 }
2207 else if(upper_c == KEY_DEL)
2208 {
2209 if(ctrl)
2210 {
2211 s[0] = 0;
2212 scursor = 0;
2213 ecursor = -1;
2214 GUI_EVENT(d, geCHANGE_VALUE);
2215 }
2216 else if(range_selected)
2217 {
2218 ecursor = -1;
2219 scursor = low_cursor;
2220 size_t ind = low_cursor, ind2 = high_cursor+1;
2221 while(ind2 < l && s[ind2])
2222 s[ind++] = s[ind2++];
2223 while(s[ind])
2224 s[ind++] = 0;
2225 GUI_EVENT(d, geCHANGE_VALUE);
2226 }
2227 else if(scursor < l)
2228 {
2229 for(p=scursor; s[p]; p++)
2230 s[p] = s[p+1];
2231 GUI_EVENT(d, geCHANGE_VALUE);
2232 }
2233 }
2234 else if(upper_c == KEY_BACKSPACE)
2235 {
2236 if(line_modifier)
2237 {
2238 delete_line(s, &scursor);
2239 ecursor = -1;
2240 GUI_EVENT(d, geCHANGE_VALUE);
2241 }
2242 else if(word_modifier)
2243 {
2244 delete_word(s, &scursor);
2245 ecursor = -1;
2246 GUI_EVENT(d, geCHANGE_VALUE);
2247 }
2248 else if(range_selected)
2249 {
2250 ecursor = -1;
2251 scursor = low_cursor;
2252 size_t ind = low_cursor, ind2 = high_cursor+1;
2253 while(ind2 < l && s[ind2])
2254 s[ind++] = s[ind2++];
2255 while(s[ind])
2256 s[ind++] = 0;
2257 GUI_EVENT(d, geCHANGE_VALUE);
2258 }
2259 else if(scursor > 0)
2260 {
2261 --scursor;
2262 for(p=scursor; s[p]; p++)
2263 s[p] = s[p+1];
2264 GUI_EVENT(d, geCHANGE_VALUE);
2265 }
2266 }
2267 else if(upper_c == KEY_ENTER)
2268 {
2269 change_cursor = false;
2270 GUI_EVENT(d, geENTER);
2271 if(d->flags & D_EXIT)
2272 {
2273 object_message(d, MSG_DRAW, 0);
2274 return D_CLOSE;
2275 }
2276 else
2277 return D_O_K;
2278 }
2279 else if(upper_c == KEY_TAB)
2280 {
2281 change_cursor = false;
2282 return D_O_K;
2283 }
2284 else if(ctrl && lower_c == KEY_C)
2285 {
2286 change_cursor = false;
2287 std::ostringstream oss;
2288 if(range_selected)
2289 {
2290 for(size_t ind = low_cursor; ind <= high_cursor; ++ind)
2291 {
2292 if(s[ind])
2293 oss << s[ind];
2294 }
2295 }
2296 else
2297 {
2298 if(s[scursor])
2299 oss << s[scursor];
2300 }
2301 set_al_clipboard(oss.str());
2302 }
2303 else if(clipboard_has_text() && ctrl && lower_c == KEY_V)
2304 {
2305 std::string cb;
2306 if(get_al_clipboard(cb))
2307 {
2308 int ind = low_cursor, ind2 = high_cursor + 1;
2309 if (range_selected)
2310 {
2311 //Delete selected text
2312 ecursor = -1;
2313 scursor = low_cursor;
2314 while (s[ind2] && ind2 < l)
2315 s[ind++] = s[ind2++];
2316 while (s[ind])
2317 s[ind++] = 0;
2318 l = (int32_t)strlen(s);
2319 }
2320 //Move the text out of the way of the pasting
2321 int paste_len = cb.size();
2322 int paste_start = scursor;
2323 int paste_end = paste_start+paste_len;
2324 ind = strlen(s);
2325 ind2 = ind+paste_len;
2326 while(ind2 > d->d1)
2327 {
2328 --ind;
2329 --ind2;
2330 }
2331 size_t new_l = ind2;
2332 while(ind >= paste_start)
2333 {
2334 if(s[ind] || (ind&&s[ind-1]))
2335 {
2336 s[ind2] = s[ind];
2337 }
2338 --ind2; --ind;
2339 }
2340 for(auto q = 0; q < paste_len && paste_start+q < new_l; ++q)
2341 {
2342 s[paste_start+q] = cb.at(q);
2343 }
2344 s[new_l] = 0;
2345 scursor = paste_start + paste_len;
2346 ecursor = -1;
2347 GUI_EVENT(d, geCHANGE_VALUE);
2348 }
2349 }
2350 else if(ctrl && lower_c == KEY_A)
2351 {
2352 cursor_start = 0;
2353 cursor_end = (int16_t)strlen((char*)d->dp) - 1;
2354 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2355 d->flags |= D_DIRTY;
2356 break;
2357 }
2358 else if(lower_c >= 32)
2359 {
2360 if(range_selected)
2361 {
2362 //Delete selected text
2363 ecursor = -1;
2364 scursor = low_cursor;
2365 size_t ind = low_cursor, ind2 = high_cursor+1;
2366 while(ind2 < l && s[ind2])
2367 s[ind++] = s[ind2++];
2368 while(s[ind])
2369 s[ind++] = 0;
2370 l = (int32_t)strlen(s);
2371 //Type the character in its' place
2372 //(fallthrough)
2373 }
2374 if(l < d->d1)
2375 {
2376 ecursor = -1;
2377 s[l+1] = 0;
2378 size_t ind = l;
2379 while(ind >= scursor)
2380 {
2381 s[ind+1] = s[ind];
2382 if (!ind) break;
2383 --ind;
2384 }
2385
2386 s[scursor++] = lower_c;
2387
2388 GUI_EVENT(d, geCHANGE_VALUE);
2389 }
2390 }
2391 else
2392 return D_O_K;
2393
2394 if(change_cursor)
2395 {
2396 if (cursor_start != scursor)
2397 d->flags |= D_DIRTY;
2398
2399 cursor_end = ecursor; cursor_start = scursor;
2400 if (cursor_end == cursor_start) cursor_end = -1;
2401 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2402 }
2403
2404 /* if we changed something, better redraw... */
2405 object_message(d, MSG_DRAW, 0);
2406 return D_USED_CHAR;
2407 }
2408 }
2409
2410 return D_O_K;
2411 }
2412
2413 /* jwin_edit_proc:
2414 * An editable text object (the dp field points to the string). When it
2415 * has the input focus (obtained by clicking on it with the mouse), text
2416 * can be typed into this object. The d1 field specifies the maximum
2417 * number of characters that it will accept, and d2 is the text cursor
2418 * position within the string.
2419 */
2420 int32_t jwin_edit_proc(int32_t msg, DIALOG *d, int32_t c)
2421 {
2422 if(d->flags & D_HIDDEN)
2423 {
2424 switch(msg)
2425 {
2426 case MSG_CHAR: case MSG_UCHAR: case MSG_XCHAR: case MSG_DRAW: case MSG_CLICK: case MSG_DCLICK: case MSG_KEY: case MSG_WANTFOCUS:
2427 return D_O_K;
2428 }
2429 }
2430 if(d->h >= 2+((text_height(d->dp2 ? (FONT*)d->dp2 : font)+2)*2))
2431 return jwin_vedit_proc(msg, d, c);
2432 int32_t f, l, p, w, x, y, fg, bg, fg2 = -1, bg2 = -1, fg3, bg3;
2433 int32_t b;
2434 int32_t scroll;
2435 char *s;
2436 char buf[2];
2437 static char nullbuf[2];
2438 sprintf(nullbuf, " ");
2439
2440 if(d->dp==NULL)
2441 {
2442 d->dp=(void *)nullbuf;
2443 }
2444
2445 s = (char*)d->dp;
2446 l = (int32_t)strlen(s);
2447
2448 int32_t cursor_start = d->d2 & 0x0000FFFF;
2449 int32_t cursor_end = int32_t((d->d2 & 0xFFFF0000) >> 16);
2450 // This was previously doing bitshifts on -1. There wasn't enough space so I cannibalized 0xFFFF instead. -Moosh
2451 if (cursor_start == 0xFFFF)
2452 cursor_start = -1;
2453 if (cursor_end == 0xFFFF)
2454 cursor_end = -1;
2455
2456 if(cursor_start > l)
2457 cursor_start = l;
2458 if(cursor_end > l)
2459 cursor_end = l;
2460 auto low_cursor = cursor_start<0 ? cursor_end : (cursor_end<0 ? cursor_start : (zc_min(cursor_start, cursor_end)));
2461 auto high_cursor = zc_max(cursor_start,cursor_end);
2462
2463 /* calculate maximal number of displayable characters */
2464 b = x = 0;
2465
2466 if(cursor_start == l)
2467 {
2468 buf[0] = ' ';
2469 buf[1] = 0;
2470
2471 if(d->dp2)
2472 x = text_length((FONT*)d->dp2, buf);
2473 else
2474 x = text_length(font, buf);
2475 }
2476
2477 buf[1] = 0;
2478
2479 for(p=cursor_start; p>=0; p--)
2480 {
2481 buf[0] = s[p];
2482 b++;
2483
2484 if(d->dp2)
2485 x += text_length((FONT*)d->dp2, buf);
2486 else
2487 x += text_length(font, buf);
2488
2489 if(x > d->w-6)
2490 break;
2491 }
2492
2493 if(x <= d->w-6)
2494 {
2495 b = l;
2496 scroll = FALSE;
2497 }
2498 else
2499 {
2500 b--;
2501 scroll = TRUE;
2502 }
2503
2504 FONT *oldfont = font;
2505 static bool dclick = false;
2506 switch(msg)
2507 {
2508 case MSG_START:
2509 dclick = false;
2510 cursor_start = (int32_t)strlen((char*)d->dp);
2511 cursor_end = -1;
2512 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2513 break;
2514
2515 case MSG_DRAW:
2516 {
2517 if(d->dp2)
2518 {
2519 font = (FONT*)d->dp2;
2520 }
2521 if(d->flags & D_DISABLED)
2522 {
2523 fg2 = scheme[jcLIGHT];
2524 bg2 = scheme[jcDISABLED_BG];
2525 fg = scheme[jcDISABLED_FG];
2526 bg = -1;
2527 fg3 = fg;
2528 bg3 = bg2;
2529 }
2530 else if(d->flags & D_READONLY)
2531 {
2532 fg = scheme[jcALT_TEXTFG];
2533 bg = scheme[jcALT_TEXTBG];
2534 fg3 = fg;
2535 bg3 = bg;
2536 }
2537 else
2538 {
2539 fg = scheme[jcTEXTFG];
2540 bg = scheme[jcTEXTBG];
2541 fg3 = fg;
2542 bg3 = bg;
2543 }
2544
2545 x = 3;
2546 y = (d->h - text_height(font)) / 2 + d->y;
2547
2548 /* first fill in the edges */
2549
2550 rectfill(screen, d->x+2, d->y+2, d->x+d->w-3, d->y+d->h-3, bg3);
2551
2552 vline(screen, d->x+2, d->y+2, d->y+d->h-3, bg3);
2553
2554 /* now the text */
2555
2556 if(scroll)
2557 {
2558 p = cursor_start-b+1;
2559 b = cursor_start;
2560 }
2561 else
2562 p = 0;
2563 for(; p<=b; p++)
2564 {
2565 buf[0] = s[p] ? s[p] : ' ';
2566 w = text_length(font, buf);
2567
2568 if(x+w > d->w)
2569 break;
2570 bool focused = (cursor_end>-1)
2571 ? (p >= low_cursor && p <= high_cursor)
2572 : (p == cursor_start);
2573 f = fg2 < 0 && (focused && (d->flags & D_GOTFOCUS));
2574 if(fg2 > -1)
2575 {
2576 textout_ex(screen, font, buf, d->x+x+1, y+1, fg2, bg2);
2577 }
2578 textout_ex(screen, font, buf, d->x+x, y, f ? bg : fg,f ? fg : bg);
2579 x += w;
2580 }
2581
2582 if(x < d->w-2)
2583 rectfill(screen, d->x+x, y, d->x+d->w-3, y+text_height(font)-1, bg3);
2584
2585 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DEEP);
2586 font = oldfont;
2587 break;
2588 }
2589
2590 case MSG_DCLICK:
2591 if ((gui_mouse_b() & 2) != 0)
2592 break;
2593 if (d->flags & (D_DISABLED | D_READONLY))
2594 break;
2595 dclick = true;
2596 break;
2597 case MSG_CLICK:
2598 {
2599 if(d->flags & (D_DISABLED|D_READONLY))
2600 break;
2601 x = d->x+3;
2602
2603 if(scroll)
2604 {
2605 p = cursor_start-b+1;
2606 b = cursor_start;
2607 }
2608 else
2609 p = 0;
2610
2611 for(; p<b; p++)
2612 {
2613 buf[0] = s[p];
2614 x += text_length((d->dp2) ? (FONT*)d->dp2 : font, buf);
2615
2616 if(x > gui_mouse_x())
2617 break;
2618 }
2619
2620 if(key_shifts&KB_SHIFT_FLAG)
2621 cursor_end = MID(0, p, l);
2622 else
2623 {
2624 cursor_end = -1;
2625 cursor_start = MID(0, p, l);
2626 if (dclick)
2627 cursor_end = cursor_start;
2628 }
2629
2630 if (dclick)
2631 {
2632 while (cursor_start > 0 && cursor_start < l)
2633 {
2634 if (s[cursor_start] == ' ')
2635 {
2636 if (cursor_start <= cursor_end)
2637 ++cursor_start;
2638 else
2639 --cursor_start;
2640 break;
2641 }
2642 if (cursor_start <= cursor_end)
2643 --cursor_start;
2644 else
2645 ++cursor_start;
2646 }
2647 while (cursor_end > 0 && cursor_end < l)
2648 {
2649 if (s[cursor_end] == ' ')
2650 {
2651 if (cursor_end >= cursor_start)
2652 --cursor_end;
2653 else
2654 ++cursor_end;
2655 break;
2656 }
2657 if (cursor_end >= cursor_start)
2658 ++cursor_end;
2659 else
2660 --cursor_end;
2661 }
2662 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2663 d->flags |= D_DIRTY;
2664 }
2665 else
2666 {
2667 if (cursor_end == cursor_start) cursor_end = -1;
2668 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2669 }
2670 d->flags |= D_DIRTY;
2671 dclick = false;
2672 break;
2673 }
2674
2675 case MSG_WANTFOCUS:
2676 case MSG_LOSTFOCUS:
2677 case MSG_KEY:
2678 if(d->flags & (D_DISABLED|D_READONLY))
2679 break;
2680 return D_WANTFOCUS;
2681
2682 case MSG_CHAR:
2683 {
2684 if(d->flags & (D_DISABLED|D_READONLY))
2685 break;
2686 bool shifted = key_shifts & KB_SHIFT_FLAG;
2687 bool ctrl = key_shifts & KB_CTRL_FLAG;
2688 bool word_modifier = key_shifts & WORD_FLAG;
2689 bool line_modifier = key_shifts & LINE_FLAG;
2690 bool change_cursor = true;
2691 bool change_value = false;
2692 int scursor = cursor_start, ecursor = cursor_end;
2693 bool range_selected = cursor_end > -1;
2694 auto upper_c = c>>8;
2695 auto lower_c = c&0xFF;
2696 if(shifted)
2697 {
2698 if(ecursor < 0)
2699 ecursor = scursor;
2700 }
2701 if(upper_c == KEY_LEFT)
2702 {
2703 if(shifted)
2704 {
2705 if(ecursor>0)
2706 --ecursor;
2707 }
2708 else
2709 {
2710 ecursor = -1;
2711 if(scursor > 0)
2712 --scursor;
2713 }
2714 }
2715 else if(upper_c == KEY_RIGHT)
2716 {
2717 if(shifted)
2718 {
2719 if(ecursor < l)
2720 ++ecursor;
2721 }
2722 else
2723 {
2724 ecursor = -1;
2725 if(scursor < l)
2726 ++scursor;
2727 }
2728 }
2729 else if(upper_c == KEY_HOME)
2730 {
2731 if(shifted)
2732 ecursor = 0;
2733 else
2734 {
2735 ecursor = -1;
2736 scursor = 0;
2737 }
2738 }
2739 else if(upper_c == KEY_END)
2740 {
2741 if(shifted)
2742 ecursor = l;
2743 else
2744 {
2745 ecursor = -1;
2746 scursor = l;
2747 }
2748 }
2749 else if(upper_c == KEY_DEL)
2750 {
2751 if(ctrl)
2752 {
2753 s[0] = 0;
2754 scursor = 0;
2755 ecursor = -1;
2756 GUI_EVENT(d, geCHANGE_VALUE);
2757 change_value = true;
2758 }
2759 else if(range_selected)
2760 {
2761 ecursor = -1;
2762 scursor = low_cursor;
2763 int ind = low_cursor, ind2 = high_cursor+1;
2764 ind2 = std::min(ind2, d->d1 - 1);
2765 while(s[ind2])
2766 s[ind++] = s[ind2++];
2767 while(s[ind])
2768 s[ind++] = 0;
2769 GUI_EVENT(d, geCHANGE_VALUE);
2770 change_value = true;
2771 }
2772 else if(scursor < l)
2773 {
2774 for(p=scursor; s[p]; p++)
2775 s[p] = s[p+1];
2776 GUI_EVENT(d, geCHANGE_VALUE);
2777 change_value = true;
2778 }
2779 }
2780 else if(upper_c == KEY_BACKSPACE)
2781 {
2782 if(line_modifier)
2783 {
2784 delete_line(s, &scursor);
2785 ecursor = -1;
2786 GUI_EVENT(d, geCHANGE_VALUE);
2787 change_value = true;
2788 }
2789 else if(word_modifier)
2790 {
2791 delete_word(s, &scursor);
2792 ecursor = -1;
2793 GUI_EVENT(d, geCHANGE_VALUE);
2794 change_value = true;
2795 }
2796 else if(range_selected)
2797 {
2798 ecursor = -1;
2799 scursor = low_cursor;
2800 size_t ind = low_cursor, ind2 = high_cursor+1;
2801 while(ind2 < l && s[ind2])
2802 s[ind++] = s[ind2++];
2803 while(s[ind])
2804 s[ind++] = 0;
2805 GUI_EVENT(d, geCHANGE_VALUE);
2806 change_value = true;
2807 }
2808 else if(scursor > 0)
2809 {
2810 --scursor;
2811 for(p=scursor; s[p]; p++)
2812 s[p] = s[p+1];
2813 GUI_EVENT(d, geCHANGE_VALUE);
2814 change_value = true;
2815 }
2816 }
2817 else if(upper_c == KEY_ENTER)
2818 {
2819 change_cursor = false;
2820 GUI_EVENT(d, geENTER);
2821 if(d->flags & D_EXIT)
2822 {
2823 object_message(d, MSG_DRAW, 0);
2824 return D_CLOSE;
2825 }
2826 else
2827 return D_O_K;
2828 }
2829 else if(upper_c == KEY_TAB)
2830 {
2831 change_cursor = false;
2832 return D_O_K;
2833 }
2834 else if(ctrl && lower_c == KEY_C)
2835 {
2836 change_cursor = false;
2837 std::ostringstream oss;
2838 if(range_selected)
2839 {
2840 for(size_t ind = low_cursor; ind <= high_cursor; ++ind)
2841 {
2842 if(s[ind])
2843 oss << s[ind];
2844 }
2845 }
2846 else
2847 {
2848 if(s[scursor])
2849 oss << s[scursor];
2850 }
2851 set_al_clipboard(oss.str());
2852 }
2853 else if(clipboard_has_text() && ctrl && lower_c == KEY_V)
2854 {
2855 std::string cb;
2856 if(get_al_clipboard(cb))
2857 {
2858 int ind = low_cursor, ind2 = high_cursor + 1;
2859 if (range_selected)
2860 {
2861 //Delete selected text
2862 ecursor = -1;
2863 scursor = low_cursor;
2864 while (s[ind2] && ind2 < l)
2865 s[ind++] = s[ind2++];
2866 while (s[ind])
2867 s[ind++] = 0;
2868 l = (int32_t)strlen(s);
2869 }
2870 //Move the text out of the way of the pasting
2871 int paste_len = cb.size();
2872 int paste_start = scursor;
2873 int paste_end = paste_start+paste_len;
2874 ind = strlen(s);
2875 ind2 = ind+paste_len;
2876 while(ind2 > d->d1)
2877 {
2878 --ind;
2879 --ind2;
2880 }
2881 size_t new_l = ind2;
2882 while(ind >= paste_start)
2883 {
2884 if(s[ind] || (ind&&s[ind-1]))
2885 {
2886 s[ind2] = s[ind];
2887 }
2888 --ind2; --ind;
2889 }
2890 for(auto q = 0; q < paste_len && paste_start+q < new_l; ++q)
2891 {
2892 s[paste_start+q] = cb.at(q);
2893 }
2894 s[new_l] = 0;
2895 scursor = paste_start + paste_len;
2896 ecursor = -1;
2897 GUI_EVENT(d, geCHANGE_VALUE);
2898 change_value = true;
2899 }
2900 }
2901 else if(ctrl && lower_c == KEY_A)
2902 {
2903 cursor_start = 0;
2904 cursor_end = (int16_t)strlen((char*)d->dp) - 1;
2905 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2906 d->flags |= D_DIRTY;
2907 break;
2908 }
2909 else if(lower_c >= 32)
2910 {
2911 if(range_selected)
2912 {
2913 //Delete selected text
2914 ecursor = -1;
2915 scursor = low_cursor;
2916 int ind = low_cursor, ind2 = high_cursor+1;
2917 // ind2 = std::min(ind2, d->d1);
2918 while(s[ind2] && ind2 < l)
2919 s[ind++] = s[ind2++];
2920 while(s[ind])
2921 s[ind++] = 0;
2922 l = (int32_t)strlen(s);
2923 //Type the character in its' place
2924 //(fallthrough)
2925 }
2926 if(l < d->d1)
2927 {
2928 ecursor = -1;
2929 s[l+1] = 0;
2930 size_t ind = l;
2931 while(ind >= scursor)
2932 {
2933 s[ind+1] = s[ind];
2934 if (!ind) break;
2935 --ind;
2936 }
2937
2938 s[scursor++] = lower_c;
2939
2940 GUI_EVENT(d, geCHANGE_VALUE);
2941 change_value = true;
2942 }
2943 }
2944 else
2945 return D_O_K;
2946 if(change_cursor)
2947 {
2948 cursor_end = ecursor; cursor_start = scursor;
2949 if (cursor_end == cursor_start) cursor_end = -1;
2950 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2951 }
2952 /* if we changed something, better redraw... */
2953 // Note: this still redraws when not necessary.
2954 if (change_value || change_cursor)
2955 d->flags |= D_DIRTY;
2956 return D_USED_CHAR;
2957 }
2958 }
2959 return D_O_K;
2960 }
2961
2962 int32_t jwin_hexedit_proc_old(int32_t msg,DIALOG *d,int32_t c)
2963 {
2964 if(msg==MSG_CHAR)
2965 if(((isalpha(c&255) && !isxdigit(c&255))) || ispunct(c&255))
2966 return D_USED_CHAR;
2967
2968 return jwin_edit_proc(msg,d,isalpha(c&255)?c&0xDF:c);
2969 }
2970
2971 bool editproc_special_key(int32_t c)
2972 {
2973 switch(c>>8)
2974 {
2975 case KEY_LEFT: case KEY_RIGHT:
2976 case KEY_HOME: case KEY_END:
2977 case KEY_DEL: case KEY_BACKSPACE:
2978 case KEY_ENTER: case KEY_TAB:
2979 return true;
2980 }
2981 if(key_shifts & KB_CTRL_FLAG)
2982 switch(c&255)
2983 {
2984 case 'c': case 'C':
2985 return true;
2986 case 'v': case 'V':
2987 return clipboard_has_text();
2988 }
2989 return false;
2990 }
2991 bool editproc_combined_key(int32_t c)
2992 {
2993 if(key_shifts & KB_CTRL_FLAG)
2994 switch(c&255)
2995 {
2996 case 'c': case 'C':
2997 return true;
2998 case 'v': case 'V':
2999 return clipboard_has_text();
3000 }
3001 return false;
3002 }
3003 int32_t jwin_hexedit_proc(int32_t msg,DIALOG *d,int32_t c)
3004 {
3005 bool caps_paste = false;
3006 if(msg==MSG_CHAR)
3007 {
3008 if(key_shifts & KB_CTRL_FLAG)
3009 {
3010 if(clipboard_has_text() && ((c&255)=='v' || (c&255)=='V'))
3011 {
3012 std::string cb;
3013 if(get_al_clipboard(cb))
3014 {
3015 if(cb.find_first_not_of("-.0123456789ABCDEFabcdef") != std::string::npos)
3016 return D_USED_CHAR;
3017 if(cb.find_first_of("abcdef") != std::string::npos)
3018 caps_paste = true;
3019 }
3020 else return D_USED_CHAR;
3021 }
3022 }
3023 switch(c&255)
3024 {
3025 case '-': case '.':
3026 case '0': case '1': case '2': case '3': case '4':
3027 case '5': case '6': case '7': case '8': case '9':
3028 case 'A': case 'B': case 'C':
3029 case 'D': case 'E': case 'F':
3030 break;
3031 case 'a': case 'b': case 'c':
3032 case 'd': case 'e': case 'f':
3033 c = (c&~255)|toupper(c&255);
3034 break;
3035 default:
3036 if(!editproc_special_key(c))
3037 return D_O_K;
3038 else if(!editproc_combined_key(c))
3039 c&=~255;
3040 }
3041 }
3042
3043 auto ret = jwin_edit_proc(msg,d,c);
3044 if(caps_paste)
3045 {
3046 char* s = (char*)d->dp;
3047 caps_paste = false;
3048 for(int q = strlen(s)-1; q >= 0; --q)
3049 {
3050 switch(s[q])
3051 {
3052 case 'a': case 'b': case 'c':
3053 case 'd': case 'e': case 'f':
3054 s[q] = toupper(s[q]);
3055 caps_paste = true;
3056 break;
3057 }
3058 }
3059 if(caps_paste)
3060 {
3061 jwin_edit_proc(MSG_DRAW,d,0);
3062 }
3063 }
3064 return ret;
3065 }
3066 int32_t jwin_numedit_proc(int32_t msg,DIALOG *d,int32_t c)
3067 {
3068 if(msg==MSG_CHAR)
3069 {
3070 if(key_shifts & KB_CTRL_FLAG)
3071 {
3072 if(clipboard_has_text() && ((c&255)=='v' || (c&255)=='V'))
3073 {
3074 std::string cb;
3075 if(get_al_clipboard(cb))
3076 {
3077 if(cb.find_first_not_of("-.0123456789") != std::string::npos)
3078 return D_USED_CHAR;
3079 }
3080 else return D_USED_CHAR;
3081 }
3082 }
3083 switch(c&255)
3084 {
3085 case '-': case '.':
3086 case '0': case '1': case '2': case '3': case '4':
3087 case '5': case '6': case '7': case '8': case '9':
3088 break;
3089 default:
3090 if(!editproc_special_key(c))
3091 return D_O_K;
3092 else if(!editproc_combined_key(c))
3093 c&=~255;
3094 }
3095 }
3096
3097 return jwin_edit_proc(msg,d,c);
3098 }
3099
3100 int32_t jwin_numedit_byte_proc(int32_t msg,DIALOG *d,int32_t c)
3101 {
3102 if ( (atoi((char*)d->dp)) > 255 )
3103 {
3104 strcpy((char*)d->dp,"255\0");
3105 return jwin_numedit_proc(msg,d,c);
3106 }
3107 else if ( (atoi((char*)d->dp)) < 0 )
3108 {
3109 strcpy((char*)d->dp,"0\0");
3110 return jwin_numedit_proc(msg,d,c);
3111 }
3112
3113 return jwin_numedit_proc(msg,d,c);
3114 }
3115
3116 int32_t jwin_numedit_short_proc(int32_t msg,DIALOG *d,int32_t c)
3117 {
3118 if ( (atoi((char*)d->dp)) > 65535 )
3119 {
3120 strcpy((char*)d->dp,"65535\0");
3121 return jwin_numedit_proc(msg,d,c);
3122 }
3123 else if ( (atoi((char*)d->dp)) < 0 )
3124 {
3125 strcpy((char*)d->dp,"0\0");
3126 return jwin_numedit_proc(msg,d,c);
3127 }
3128
3129 return jwin_numedit_proc(msg,d,c);
3130 }
3131
3132 int32_t jwin_numedit_zscriptint_proc(int32_t msg,DIALOG *d,int32_t c)
3133 {
3134 if ( (atoi((char*)d->dp)) > 214748 )
3135 {
3136 strcpy((char*)d->dp,"214748\0");
3137 return jwin_numedit_proc(msg,d,c);
3138 }
3139 else if ( (atoi((char*)d->dp)) < -214748 )
3140 {
3141 strcpy((char*)d->dp,"-214748\0");
3142 return jwin_numedit_proc(msg,d,c);
3143 }
3144
3145 return jwin_numedit_proc(msg,d,c);
3146 }
3147
3148 int32_t jwin_numedit_sshort_proc(int32_t msg,DIALOG *d,int32_t c)
3149 {
3150 if ( (atoi((char*)d->dp)) > 32767 )
3151 {
3152 strcpy((char*)d->dp,"32767\0");
3153 return jwin_numedit_proc(msg,d,c);
3154 }
3155 else if ( (atoi((char*)d->dp)) < -32768 )
3156 {
3157 strcpy((char*)d->dp,"-32768\0");
3158 return jwin_numedit_proc(msg,d,c);
3159 }
3160
3161 return jwin_numedit_proc(msg,d,c);
3162 }
3163
3164 int32_t jwin_numedit_sbyte_proc(int32_t msg,DIALOG *d,int32_t c)
3165 {
3166 if ( (atoi((char*)d->dp)) > 127 )
3167 {
3168 strcpy((char*)d->dp,"127\0");
3169 return jwin_numedit_proc(msg,d,c);
3170 }
3171 else if ( (atoi((char*)d->dp)) < -128 )
3172 {
3173 strcpy((char*)d->dp,"-128\0");
3174 return jwin_numedit_proc(msg,d,c);
3175 }
3176
3177 return jwin_numedit_proc(msg,d,c);
3178 }
3179
3180 // Special numedit procs
3181
3182 void trim_trailing_0s(char* str, bool leaveDec = false)
3183 {
3184 bool foundDec = false;
3185 for(int32_t q = 0; str[q]; ++q)
3186 {
3187 if(str[q] == '.')
3188 {
3189 foundDec = true;
3190 break;
3191 }
3192 }
3193 if(!foundDec) return; //No decimal place, thus no trailing 0's.
3194 for(int32_t q = strlen(str)-1; q > 0; --q)
3195 {
3196 if(str[q] == '0' && (!leaveDec || str[q-1] != '.'))
3197 {
3198 str[q] = 0;
3199 }
3200 else if(str[q] == '.')
3201 {
3202 str[q] = 0;
3203 return;
3204 }
3205 else return;
3206 }
3207 }
3208 int32_t jwin_swapbtn_proc(int32_t msg, DIALOG* d, int32_t c)
3209 {
3210 static const char* swp[nswapMAX] = {"D", "H", "LD", "LH", "B"};
3211 d->dp = (void*)swp[d->d1&0xF];
3212 //d1 is (0xF0 = old val, 0x0F = new val)
3213 //d2 is max val
3214 if(d->d2 < 2 || d->d2 > nswapMAX) return D_O_K; //Not setup yet, or bad value
3215 DIALOG* relproc = (DIALOG*)d->dp3;
3216 GUI::TextField *tf_obj = nullptr;
3217 if(d->d2 > nswapBOOL) tf_obj = (GUI::TextField*)relproc->dp3;
3218 int32_t ret = jwin_button_proc(msg, d, c);
3219 if(d->flags & D_SELECTED) //On selection
3220 {
3221 d->d1 = ((d->d1&0x0F)<<4) | (((d->d1&0x0F)+1)%d->d2);
3222 d->dp = (void*)swp[d->d1&0xF];
3223 d->flags &= ~D_SELECTED;
3224 if(tf_obj) tf_obj->refresh_cb_swap();
3225 if(relproc)
3226 {
3227 object_message(relproc, MSG_DRAW, 0);
3228 }
3229 object_message(d, MSG_DRAW, 0);
3230 }
3231 return ret;
3232 }
3233 int32_t jwin_numedit_swap_byte_proc(int32_t msg, DIALOG *d, int32_t c)
3234 {
3235 DIALOG* swapbtn;
3236 if(d->flags&D_NEW_GUI)
3237 {
3238 swapbtn = d+1;
3239 }
3240 else swapbtn = (DIALOG*)d->dp3;
3241 if(!swapbtn) return D_O_K;
3242 if(msg==MSG_START) //Setup the swapbtn
3243 {
3244 d->bg = 0;
3245 swapbtn->d2 = 2; //Max states
3246 auto ty = swapbtn->d1&0xF;
3247 if(unsigned(ty) > swapbtn->d2)
3248 swapbtn->d1 &= ~0xF;
3249 swapbtn->dp3 = (void*)d;
3250 }
3251 int32_t ret = D_O_K;
3252 int32_t ntype = swapbtn->d1&0xF,
3253 otype = swapbtn->d1>>4;
3254
3255 char* str = (char*)d->dp;
3256 int32_t v = 0;
3257 if(msg == MSG_START)
3258 v = d->fg;
3259 else switch(otype)
3260 {
3261 case nswapDEC:
3262 v = atoi(str);
3263 break;
3264 case nswapHEX:
3265 v = zc_xtoi(str);
3266 break;
3267 }
3268 byte b;
3269 if ( v > 255 )
3270 b=255;
3271 else if ( v < 0 )
3272 b=0;
3273 else b = (byte)v;
3274 if(msg==MSG_CHAR && ((c&255)=='-'))
3275 {
3276 //unsigned//b = -b;
3277 c &= ~255;
3278 }
3279 if(unsigned(v) != b || otype != ntype || msg == MSG_START)
3280 {
3281 switch(ntype)
3282 {
3283 case nswapDEC:
3284 sprintf(str, "%d", b);
3285 break;
3286 case nswapHEX:
3287 sprintf(str, "%X", b);
3288 break;
3289 }
3290 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3291 }
3292
3293 if(d->fg != b)
3294 {
3295 d->fg = b; //Store numeric data
3296 GUI_EVENT(d, geUPDATE_SWAP);
3297 }
3298 switch(ntype)
3299 {
3300 case nswapDEC:
3301 d->d1 = 3; //3 digits max
3302 ret |= jwin_numedit_proc(msg, d, c);
3303 break;
3304 case nswapHEX:
3305 d->d1 = 2; //2 digits max
3306 if(msg == MSG_CHAR && isalpha(c&255)) //always capitalize
3307 c = (c&~255) | (toupper(c&255));
3308 ret |= jwin_hexedit_proc(msg, d, c);
3309 break;
3310 }
3311
3312 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3313
3314 return ret;
3315 }
3316 #define INC_TF_CURSORS(val,inc,max) \
3317 do \
3318 { \
3319 int32_t scursor = (val & 0xFFFF)+inc; \
3320 int32_t ecursor = (val & 0xFFFF0000) >> 16; \
3321 bool valid_ecursor = ecursor != 0xFFFF; \
3322 if(valid_ecursor) ecursor += inc; \
3323 if(inc < 0) \
3324 { \
3325 if(scursor < 0) scursor = 0; \
3326 if(valid_ecursor && ecursor < 0) ecursor = 0; \
3327 } \
3328 else \
3329 { \
3330 if(scursor > max) scursor = max; \
3331 if(valid_ecursor && ecursor > max) ecursor = max; \
3332 } \
3333 val = scursor | (ecursor<<16); \
3334 } while(false)
3335 int32_t jwin_numedit_swap_sshort_proc(int32_t msg, DIALOG *d, int32_t c)
3336 {
3337 const size_t maxlen = 7;
3338 DIALOG* swapbtn;
3339 if(d->flags&D_NEW_GUI)
3340 {
3341 swapbtn = d+1;
3342 }
3343 else swapbtn = (DIALOG*)d->dp3;
3344 if(!swapbtn) return D_O_K;
3345 if(msg==MSG_START) //Setup the swapbtn
3346 {
3347 d->bg = 0;
3348 swapbtn->d2 = 2; //Max states
3349 auto ty = swapbtn->d1&0xF;
3350 if(unsigned(ty) > swapbtn->d2)
3351 swapbtn->d1 &= ~0xF;
3352 swapbtn->dp3 = (void*)d;
3353 }
3354 int32_t ret = D_O_K;
3355 int32_t ntype = swapbtn->d1&0xF,
3356 otype = swapbtn->d1>>4;
3357
3358 char* str = (char*)d->dp;
3359 int32_t v = 0;
3360 if(msg == MSG_START)
3361 v = d->fg;
3362 else switch(otype)
3363 {
3364 case nswapDEC:
3365 v = atoi(str);
3366 break;
3367 case nswapHEX:
3368 v = zc_xtoi(str);
3369 break;
3370 }
3371 int16_t b;
3372 if ( v > 32767 )
3373 b=32767;
3374 else if ( v < -32768 )
3375 b=-32768;
3376 else b = (int16_t)v;
3377 bool queued_neg = d->bg;
3378 if(msg==MSG_CHAR && ((c&255)=='-'))
3379 {
3380 if(b)
3381 {
3382 b = -b;
3383 v = b;
3384 if(b<0)
3385 {
3386 if(str[0] != '-')
3387 {
3388 char buf[16] = {0};
3389 strcpy(buf, str);
3390 sprintf(str, "-%s", buf);
3391 INC_TF_CURSORS(d->d2,1,strlen(str));
3392 }
3393 }
3394 else if(str[0] == '-')
3395 {
3396 char buf[16] = {0};
3397 strcpy(buf, str);
3398 sprintf(str, "%s", buf+1);
3399 INC_TF_CURSORS(d->d2,-1,strlen(str));
3400 }
3401 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3402 }
3403 else queued_neg = !queued_neg; //queue the negative
3404 c &= ~255;
3405 ret |= D_USED_CHAR;
3406 }
3407 if(b && queued_neg)
3408 {
3409 //b = -b; //actually, 'atoi' handles it for us.....
3410 queued_neg = false;
3411 }
3412 if(bool(d->bg) != queued_neg)
3413 {
3414 d->bg = queued_neg;
3415 if(queued_neg)
3416 {
3417 if(str[0] != '-')
3418 {
3419 char buf[16] = {0};
3420 strcpy(buf, str);
3421 sprintf(str, "-%s", buf);
3422 INC_TF_CURSORS(d->d2,1,strlen(str));
3423 }
3424 }
3425 else if(!b && str[0] == '-')
3426 {
3427 char buf[16] = {0};
3428 strcpy(buf, str);
3429 sprintf(str, "%s", buf+1);
3430 INC_TF_CURSORS(d->d2,-1,strlen(str));
3431 }
3432 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3433 }
3434 if(v != b || otype != ntype || msg == MSG_START)
3435 {
3436 switch(ntype)
3437 {
3438 case nswapDEC:
3439 sprintf(str, "%d", b);
3440 break;
3441 case nswapHEX:
3442 if(b<0)
3443 sprintf(str, "-%X", -b);
3444 else sprintf(str, "%X", b);
3445 break;
3446 }
3447 d->d2 = 0xFFFF0000|strlen(str);
3448 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3449 }
3450
3451 if(d->fg != b)
3452 {
3453 d->fg = b; //Store numeric data
3454 GUI_EVENT(d, geUPDATE_SWAP);
3455 }
3456 bool rev_d2 = false;
3457 int32_t old_d2 = d->d2;
3458 int32_t ref_d2;
3459 if(msg == MSG_CHAR && queued_neg)
3460 {
3461 auto scursor = d->d2 & 0xFFFF;
3462 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
3463 if(!scursor)
3464 {
3465 rev_d2 = true;
3466 INC_TF_CURSORS(d->d2,1,strlen(str));
3467 ref_d2 = d->d2;
3468 }
3469 }
3470 switch(ntype)
3471 {
3472 case nswapDEC:
3473 d->d1 = 6; //6 digits max (incl '-')
3474 ret |= jwin_numedit_proc(msg, d, c);
3475 break;
3476 case nswapHEX:
3477 d->d1 = 5; //5 digits max (incl '-')
3478 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
3479 c = (c&~255) | (toupper(c&255));
3480 ret |= jwin_hexedit_proc(msg, d, c);
3481 break;
3482 }
3483 if(rev_d2 && ref_d2 == d->d2)
3484 {
3485 d->d2 = old_d2;
3486 }
3487
3488 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3489
3490 return ret;
3491 }
3492 int32_t jwin_numedit_swap_zsint_proc(int32_t msg, DIALOG *d, int32_t c)
3493 {
3494 const size_t maxlen = 13;
3495 DIALOG* swapbtn;
3496 if(d->flags&D_NEW_GUI)
3497 {
3498 swapbtn = d+1;
3499 }
3500 else swapbtn = (DIALOG*)d->dp3;
3501 if(!swapbtn) return D_O_K;
3502 if(msg==MSG_START) //Setup the swapbtn
3503 {
3504 d->bg = 0;
3505 swapbtn->d2 = 4; //Max states
3506 auto ty = swapbtn->d1&0xF;
3507 if(unsigned(ty) > swapbtn->d2)
3508 swapbtn->d1 &= ~0xF;
3509 swapbtn->dp3 = (void*)d;
3510 }
3511 int32_t ret = D_O_K;
3512 int32_t ntype = swapbtn->d1&0xF,
3513 otype = swapbtn->d1>>4;
3514
3515 char* str = (char*)d->dp;
3516 int64_t v = 0;
3517 if(msg == MSG_START)
3518 v = d->fg;
3519 else switch(otype)
3520 {
3521 case nswapDEC:
3522 if(char *ptr = strchr(str, '.'))
3523 {
3524 char tempstr[32] = {0};
3525 strcpy(tempstr, str);
3526 for(int32_t q = 0; q < 4; ++q)
3527 tempstr[strlen(str)+q]='0';
3528 ptr = strchr(tempstr, '.');
3529 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
3530 v = atoi(tempstr);
3531 v *= 10000;
3532 if(tempstr[0] == '-')
3533 v -= atoi(ptr);
3534 else v += atoi(ptr);
3535 }
3536 else
3537 {
3538 v = atoi(str);
3539 v *= 10000;
3540 }
3541 break;
3542 case nswapHEX:
3543 if(char *ptr = strchr(str, '.'))
3544 {
3545 char tempstr[32] = {0};
3546 strcpy(tempstr, str);
3547 for(int32_t q = 0; q < 4; ++q)
3548 tempstr[strlen(str)+q]='0';
3549 ptr = strchr(tempstr, '.');
3550 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
3551 v = zc_xtoi(tempstr);
3552 v *= 10000;
3553 if(tempstr[0] == '-')
3554 v -= atoi(ptr);
3555 else v += atoi(ptr);
3556 }
3557 else
3558 {
3559 v = zc_xtoi(str);
3560 v *= 10000;
3561 }
3562 break;
3563 case nswapLDEC:
3564 v = zc_atoi64(str);
3565 break;
3566 case nswapLHEX:
3567 v = zc_xtoi64(str);
3568 break;
3569 }
3570 int32_t b;
3571 if ( v > 2147483647 )
3572 b=2147483647;
3573 else if ( v < INT_MIN )
3574 b=INT_MIN;
3575 else b = (int32_t)v;
3576 bool queued_neg = d->bg;
3577 if(msg==MSG_CHAR && ((c&255)=='-'))
3578 {
3579 if(b)
3580 {
3581 if(b==INT_MIN)
3582 ++b;
3583 b = -b;
3584 v = b;
3585 if(b<0)
3586 {
3587 if(str[0] != '-')
3588 {
3589 char buf[16] = {0};
3590 strcpy(buf, str);
3591 sprintf(str, "-%s", buf);
3592 INC_TF_CURSORS(d->d2,1,strlen(str));
3593 }
3594 }
3595 else if(str[0] == '-')
3596 {
3597 char buf[16] = {0};
3598 strcpy(buf, str);
3599 sprintf(str, "%s", buf+1);
3600 INC_TF_CURSORS(d->d2,-1,strlen(str));
3601 }
3602 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3603 }
3604 else queued_neg = !queued_neg; //queue negative
3605 c &= ~255;
3606 ret |= D_USED_CHAR;
3607 }
3608 if(b && queued_neg)
3609 {
3610 //b = -b; //actually, 'atoi' handles it for us.....
3611 queued_neg = false;
3612 }
3613 if(bool(d->bg) != queued_neg)
3614 {
3615 d->bg = queued_neg;
3616 if(queued_neg)
3617 {
3618 if(str[0] != '-')
3619 {
3620 char buf[16] = {0};
3621 strcpy(buf, str);
3622 sprintf(str, "-%s", buf);
3623 INC_TF_CURSORS(d->d2,1,strlen(str));
3624 }
3625 }
3626 else if(!b && str[0] == '-')
3627 {
3628 char buf[16] = {0};
3629 strcpy(buf, str);
3630 sprintf(str, "%s", buf+1);
3631 INC_TF_CURSORS(d->d2,-1,strlen(str));
3632 }
3633 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3634 }
3635 if(v != b || otype != ntype || msg == MSG_START)
3636 {
3637 switch(ntype)
3638 {
3639 case nswapDEC:
3640 if(b < 0)
3641 sprintf(str, "-%ld.%04ld", abs(b/10000L), abs(b%10000L));
3642 else sprintf(str, "%ld.%04ld", b/10000L, b%10000L);
3643 trim_trailing_0s(str);
3644 break;
3645 case nswapHEX:
3646 if(b<0)
3647 sprintf(str, "-%lX.%04ld", abs(b/10000L), abs(b%10000L));
3648 else sprintf(str, "%lX.%04ld", b/10000L, abs(b%10000L));
3649 trim_trailing_0s(str);
3650 break;
3651 case nswapLDEC:
3652 sprintf(str, "%d", b);
3653 break;
3654 case nswapLHEX:
3655 if(b<0)
3656 sprintf(str, "-%X", -b);
3657 else sprintf(str, "%X", b);
3658 break;
3659 }
3660 d->d2 = 0xFFFF0000|strlen(str);
3661 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3662 }
3663 if(d->fg != b)
3664 {
3665 d->fg = b; //Store numeric data
3666 GUI_EVENT(d, geUPDATE_SWAP);
3667 }
3668 if(msg==MSG_CHAR && ((c&255)=='.'))
3669 {
3670 if(ntype >= nswapLDEC) //No '.' in long modes
3671 c&=~255;
3672 else
3673 {
3674 for(int32_t q = 0; str[q]; ++q)
3675 {
3676 if(str[q] == '.') //Only one '.'
3677 {
3678 c&=~255;
3679 break;
3680 }
3681 }
3682 }
3683 }
3684 bool rev_d2 = false;
3685 int32_t old_d2 = d->d2;
3686 int32_t ref_d2;
3687 if(msg == MSG_CHAR && queued_neg)
3688 {
3689 auto scursor = d->d2 & 0xFFFF;
3690 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
3691 if(!scursor)
3692 {
3693 rev_d2 = true;
3694 INC_TF_CURSORS(d->d2,1,strlen(str));
3695 ref_d2 = d->d2;
3696 }
3697 }
3698 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
3699 switch(ntype)
3700 {
3701 case nswapDEC:
3702 d->d1 = 12; //12 digits max (incl '-', '.')
3703 if(msg==MSG_CHAR && !editproc_special_key(c) && !areaselect)
3704 {
3705 int32_t p = 0;
3706 for(int32_t q = 0; str[q]; ++q)
3707 {
3708 if(str[q]=='.')
3709 {
3710 if((d->d2&0x0000FFFF) <= q)
3711 break; //typing before the '.'
3712 ++p;
3713 }
3714 else if(p) ++p;
3715 }
3716 if(p>=5) //too many chars after '.'
3717 c&=~255;
3718 }
3719 ret |= jwin_numedit_proc(msg, d, c);
3720 break;
3721 case nswapHEX:
3722 d->d1 = 11; //11 digits max (incl '-', '.')
3723 if(msg==MSG_CHAR && !editproc_special_key(c))
3724 {
3725 if(!((c&255)=='.'||isxdigit(c&255)))
3726 c&=~255;
3727 else if(isxdigit(c&255) && !isdigit(c&255))
3728 for(int32_t q = 0; q < (d->d2&0x0000FFFF) && str[q]; ++q)
3729 {
3730 if(str[q] == '.') //No hex digits to the right of the '.'
3731 {
3732 c&=~255;
3733 break;
3734 }
3735 }
3736 if((c&255) && !areaselect)
3737 {
3738 int32_t p = 0;
3739 for(int32_t q = 0; str[q]; ++q)
3740 {
3741 if(str[q]=='.')
3742 {
3743 if((d->d2&0x0000FFFF) <= q)
3744 break; //typing before the '.'
3745 ++p;
3746 }
3747 else if(p) ++p;
3748 }
3749 if(p>=5) //too many chars after '.'
3750 c&=~255;
3751 }
3752 if(isalpha(c&255)) //always capitalize
3753 c = (c&~255) | (toupper(c&255));
3754 }
3755 ret |= jwin_hexedit_proc(msg, d, c);
3756 break;
3757 case nswapLDEC:
3758 d->d1 = 11; //11 digits max (incl '-')
3759 ret |= jwin_numedit_proc(msg, d, c);
3760 break;
3761 case nswapLHEX:
3762 d->d1 = 9; //9 digits max (incl '-')
3763 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
3764 c = (c&~255) | (toupper(c&255));
3765 ret |= jwin_hexedit_proc(msg, d, c);
3766 break;
3767 }
3768 if(rev_d2 && ref_d2 == d->d2)
3769 {
3770 d->d2 = old_d2;
3771 }
3772
3773 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3774
3775 return ret;
3776 }
3777 int32_t jwin_numedit_swap_zsint_nodec_proc(int32_t msg, DIALOG *d, int32_t c)
3778 {
3779 const size_t maxlen = 7;
3780 DIALOG* swapbtn;
3781 if(d->flags&D_NEW_GUI)
3782 {
3783 swapbtn = d+1;
3784 }
3785 else swapbtn = (DIALOG*)d->dp3;
3786 if(!swapbtn) return D_O_K;
3787 if(msg==MSG_START) //Setup the swapbtn
3788 {
3789 d->bg = 0;
3790 swapbtn->d2 = 2; //Max states
3791 auto ty = swapbtn->d1&0xF;
3792 if(unsigned(ty) > swapbtn->d2)
3793 swapbtn->d1 &= ~0xF;
3794 swapbtn->dp3 = (void*)d;
3795 }
3796 int32_t ret = D_O_K;
3797 int32_t ntype = swapbtn->d1&0xF,
3798 otype = swapbtn->d1>>4;
3799
3800 char* str = (char*)d->dp;
3801 int64_t v = 0;
3802 if(msg == MSG_START)
3803 v = d->fg;
3804 else switch(otype)
3805 {
3806 case nswapDEC:
3807 v = atoi(str);
3808 v *= 10000;
3809 break;
3810 case nswapHEX:
3811 v = zc_xtoi(str);
3812 v *= 10000;
3813 break;
3814 }
3815 int32_t b;
3816 if ( v > 2147480000 )
3817 b=2147480000;
3818 else if ( v < -2147480000 )
3819 b=-2147480000;
3820 else b = (int32_t)v;
3821 bool queued_neg = d->bg;
3822 if(msg==MSG_CHAR && ((c&255)=='-'))
3823 {
3824 if(b)
3825 {
3826 if(b==INT_MIN)
3827 ++b;
3828 b = -b;
3829 v = b;
3830 if(b<0)
3831 {
3832 if(str[0] != '-')
3833 {
3834 char buf[16] = {0};
3835 strcpy(buf, str);
3836 sprintf(str, "-%s", buf);
3837 INC_TF_CURSORS(d->d2,1,strlen(str));
3838 }
3839 }
3840 else if(str[0] == '-')
3841 {
3842 char buf[16] = {0};
3843 strcpy(buf, str);
3844 sprintf(str, "%s", buf+1);
3845 INC_TF_CURSORS(d->d2,-1,strlen(str));
3846 }
3847 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3848 }
3849 else queued_neg = !queued_neg; //queue negative
3850 c &= ~255;
3851 ret |= D_USED_CHAR;
3852 }
3853 if(b && queued_neg)
3854 {
3855 //b = -b; //actually, 'atoi' handles it for us.....
3856 queued_neg = false;
3857 }
3858 if(bool(d->bg) != queued_neg)
3859 {
3860 d->bg = queued_neg;
3861 if(queued_neg)
3862 {
3863 if(str[0] != '-')
3864 {
3865 char buf[16] = {0};
3866 strcpy(buf, str);
3867 sprintf(str, "-%s", buf);
3868 INC_TF_CURSORS(d->d2,1,strlen(str));
3869 }
3870 }
3871 else if(!b && str[0] == '-')
3872 {
3873 char buf[16] = {0};
3874 strcpy(buf, str);
3875 sprintf(str, "%s", buf+1);
3876 INC_TF_CURSORS(d->d2,-1,strlen(str));
3877 }
3878 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3879 }
3880 if(v != b || otype != ntype || msg == MSG_START)
3881 {
3882 switch(ntype)
3883 {
3884 case nswapDEC:
3885 if(b < 0)
3886 sprintf(str, "-%ld", abs(b/10000L));
3887 else sprintf(str, "%ld", b/10000L);
3888 break;
3889 case nswapHEX:
3890 if(b<0)
3891 sprintf(str, "-%lX", abs(b/10000L));
3892 else sprintf(str, "%lX", b/10000L);
3893 break;
3894 }
3895 d->d2 = 0xFFFF0000|strlen(str);
3896 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3897 }
3898 if(d->fg != b)
3899 {
3900 d->fg = b; //Store numeric data
3901 GUI_EVENT(d, geUPDATE_SWAP);
3902 }
3903 if(msg==MSG_CHAR && ((c&255)=='.'))
3904 {
3905 c&=~255; //no '.' in nodec version
3906 }
3907 bool rev_d2 = false;
3908 int32_t old_d2 = d->d2;
3909 int32_t ref_d2;
3910 if(msg == MSG_CHAR && queued_neg)
3911 {
3912 auto scursor = d->d2 & 0xFFFF;
3913 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
3914 if(!scursor)
3915 {
3916 rev_d2 = true;
3917 INC_TF_CURSORS(d->d2,1,strlen(str));
3918 ref_d2 = d->d2;
3919 }
3920 }
3921 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
3922 switch(ntype)
3923 {
3924 case nswapDEC:
3925 d->d1 = 7; //7 digits max (incl '-')
3926 ret |= jwin_numedit_proc(msg, d, c);
3927 break;
3928 case nswapHEX:
3929 d->d1 = 6; //6 digits max (incl '-')
3930 if(msg==MSG_CHAR && !editproc_special_key(c))
3931 {
3932 if(!isxdigit(c&255))
3933 c&=~255;
3934 if(isalpha(c&255)) //always capitalize
3935 c = (c&~255) | (toupper(c&255));
3936 }
3937 ret |= jwin_hexedit_proc(msg, d, c);
3938 break;
3939 }
3940 if(rev_d2 && ref_d2 == d->d2)
3941 {
3942 d->d2 = old_d2;
3943 }
3944
3945 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3946
3947 return ret;
3948 }
3949 int32_t jwin_numedit_swap_zsint2_proc(int32_t msg, DIALOG *d, int32_t c)
3950 {
3951 const size_t maxlen = 13;
3952 DIALOG* swapbtn;
3953 ASSERT(d->flags&D_NEW_GUI);
3954 swapbtn = d+1;
3955 if(!swapbtn) return D_O_K;
3956 GUI::TextField *tf_obj = (GUI::TextField*)d->dp3;
3957 if(!tf_obj) return D_O_K;
3958 if(msg==MSG_START) //Setup the swapbtn
3959 {
3960 d->bg = 0;
3961 swapbtn->d2 = 5; //Max states
3962 auto ty = swapbtn->d1&0xF;
3963 if(unsigned(ty) > swapbtn->d2)
3964 swapbtn->d1 &= ~0xF;
3965 swapbtn->dp3 = (void*)d;
3966 }
3967 int32_t ret = D_O_K;
3968 int32_t ntype = swapbtn->d1&0xF,
3969 otype = swapbtn->d1>>4;
3970 if(otype==nswapBOOL || ntype == nswapBOOL)
3971 {
3972 if(otype != ntype)
3973 {
3974 tf_obj->refresh_cb_swap();
3975 }
3976 if(ntype == nswapBOOL)
3977 {
3978 swapbtn->d1 = (ntype<<4)|ntype;
3979 return D_O_K;
3980 }
3981 }
3982
3983 char* str = (char*)d->dp;
3984 int64_t v = 0;
3985 if(msg == MSG_START)
3986 v = d->fg;
3987 else switch(otype)
3988 {
3989 case nswapDEC:
3990 if(char *ptr = strchr(str, '.'))
3991 {
3992 char tempstr[32] = {0};
3993 strcpy(tempstr, str);
3994 for(int32_t q = 0; q < 4; ++q)
3995 tempstr[strlen(str)+q]='0';
3996 ptr = strchr(tempstr, '.');
3997 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
3998 v = atoi(tempstr);
3999 v *= 10000;
4000 if(tempstr[0] == '-')
4001 v -= atoi(ptr);
4002 else v += atoi(ptr);
4003 }
4004 else
4005 {
4006 v = atoi(str);
4007 v *= 10000;
4008 }
4009 break;
4010 case nswapHEX:
4011 if(char *ptr = strchr(str, '.'))
4012 {
4013 char tempstr[32] = {0};
4014 strcpy(tempstr, str);
4015 for(int32_t q = 0; q < 4; ++q)
4016 tempstr[strlen(str)+q]='0';
4017 ptr = strchr(tempstr, '.');
4018 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
4019 v = zc_xtoi(tempstr);
4020 v *= 10000;
4021 if(tempstr[0] == '-')
4022 v -= atoi(ptr);
4023 else v += atoi(ptr);
4024 }
4025 else
4026 {
4027 v = zc_xtoi(str);
4028 v *= 10000;
4029 }
4030 break;
4031 case nswapLDEC:
4032 v = zc_atoi64(str);
4033 break;
4034 case nswapLHEX:
4035 v = zc_xtoi64(str);
4036 break;
4037 case nswapBOOL:
4038 v = d->fg;
4039 break;
4040 }
4041 int32_t b;
4042 if ( v > 2147483647 )
4043 b=2147483647;
4044 else if ( v < INT_MIN )
4045 b=INT_MIN;
4046 else b = (int32_t)v;
4047 bool queued_neg = d->bg;
4048 if(msg==MSG_CHAR && ((c&255)=='-'))
4049 {
4050 if(b)
4051 {
4052 if(b==INT_MIN)
4053 ++b;
4054 b = -b;
4055 v = b;
4056 if(b<0)
4057 {
4058 if(str[0] != '-')
4059 {
4060 char buf[16] = {0};
4061 strcpy(buf, str);
4062 sprintf(str, "-%s", buf);
4063 INC_TF_CURSORS(d->d2,1,strlen(str));
4064 }
4065 }
4066 else if(str[0] == '-')
4067 {
4068 char buf[16] = {0};
4069 strcpy(buf, str);
4070 sprintf(str, "%s", buf+1);
4071 INC_TF_CURSORS(d->d2,-1,strlen(str));
4072 }
4073 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4074 }
4075 else queued_neg = !queued_neg; //queue negative
4076 c &= ~255;
4077 ret |= D_USED_CHAR;
4078 }
4079 if(b && queued_neg)
4080 {
4081 //b = -b; //actually, 'atoi' handles it for us.....
4082 queued_neg = false;
4083 }
4084 if(bool(d->bg) != queued_neg)
4085 {
4086 d->bg = queued_neg;
4087 if(queued_neg)
4088 {
4089 if(str[0] != '-')
4090 {
4091 char buf[16] = {0};
4092 strcpy(buf, str);
4093 sprintf(str, "-%s", buf);
4094 INC_TF_CURSORS(d->d2,1,strlen(str));
4095 }
4096 }
4097 else if(!b && str[0] == '-')
4098 {
4099 char buf[16] = {0};
4100 strcpy(buf, str);
4101 sprintf(str, "%s", buf+1);
4102 INC_TF_CURSORS(d->d2,-1,strlen(str));
4103 }
4104 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4105 }
4106 if(v != b || otype != ntype || msg == MSG_START)
4107 {
4108 switch(ntype)
4109 {
4110 case nswapDEC:
4111 if(b < 0)
4112 sprintf(str, "-%ld.%04ld", abs(b/10000L), abs(b%10000L));
4113 else sprintf(str, "%ld.%04ld", b/10000L, b%10000L);
4114 trim_trailing_0s(str);
4115 break;
4116 case nswapHEX:
4117 if(b<0)
4118 sprintf(str, "-%lX.%04ld", abs(b/10000L), abs(b%10000L));
4119 else sprintf(str, "%lX.%04ld", b/10000L, abs(b%10000L));
4120 trim_trailing_0s(str);
4121 break;
4122 case nswapLDEC:
4123 sprintf(str, "%d", b);
4124 break;
4125 case nswapLHEX:
4126 if(b<0)
4127 sprintf(str, "-%X", -b);
4128 else sprintf(str, "%X", b);
4129 break;
4130 }
4131 d->d2 = 0xFFFF0000|strlen(str);
4132 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4133 }
4134 if(d->fg != b)
4135 {
4136 d->fg = b; //Store numeric data
4137 GUI_EVENT(d, geUPDATE_SWAP);
4138 }
4139 if(msg==MSG_CHAR && ((c&255)=='.'))
4140 {
4141 if(ntype >= nswapLDEC) //No '.' in long modes
4142 c&=~255;
4143 else
4144 {
4145 for(int32_t q = 0; str[q]; ++q)
4146 {
4147 if(str[q] == '.') //Only one '.'
4148 {
4149 c&=~255;
4150 break;
4151 }
4152 }
4153 }
4154 }
4155 bool rev_d2 = false;
4156 int32_t old_d2 = d->d2;
4157 int32_t ref_d2;
4158 if(msg == MSG_CHAR && queued_neg)
4159 {
4160 auto scursor = d->d2 & 0xFFFF;
4161 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
4162 if(!scursor)
4163 {
4164 rev_d2 = true;
4165 INC_TF_CURSORS(d->d2,1,strlen(str));
4166 ref_d2 = d->d2;
4167 }
4168 }
4169 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
4170 switch(ntype)
4171 {
4172 case nswapDEC:
4173 d->d1 = 12; //12 digits max (incl '-', '.')
4174 if(msg==MSG_CHAR && !editproc_special_key(c) && !areaselect)
4175 {
4176 int32_t p = 0;
4177 for(int32_t q = 0; str[q]; ++q)
4178 {
4179 if(str[q]=='.')
4180 {
4181 if((d->d2&0x0000FFFF) <= q)
4182 break; //typing before the '.'
4183 ++p;
4184 }
4185 else if(p) ++p;
4186 }
4187 if(p>=5) //too many chars after '.'
4188 c&=~255;
4189 }
4190 ret |= jwin_numedit_proc(msg, d, c);
4191 break;
4192 case nswapHEX:
4193 d->d1 = 11; //11 digits max (incl '-', '.')
4194 if(msg==MSG_CHAR && !editproc_special_key(c))
4195 {
4196 if(!((c&255)=='.'||isxdigit(c&255)))
4197 c&=~255;
4198 else if(isxdigit(c&255) && !isdigit(c&255))
4199 for(int32_t q = 0; q < (d->d2&0x0000FFFF) && str[q]; ++q)
4200 {
4201 if(str[q] == '.') //No hex digits to the right of the '.'
4202 {
4203 c&=~255;
4204 break;
4205 }
4206 }
4207 if((c&255) && !areaselect)
4208 {
4209 int32_t p = 0;
4210 for(int32_t q = 0; str[q]; ++q)
4211 {
4212 if(str[q]=='.')
4213 {
4214 if((d->d2&0x0000FFFF) <= q)
4215 break; //typing before the '.'
4216 ++p;
4217 }
4218 else if(p) ++p;
4219 }
4220 if(p>=5) //too many chars after '.'
4221 c&=~255;
4222 }
4223 if(isalpha(c&255)) //always capitalize
4224 c = (c&~255) | (toupper(c&255));
4225 }
4226 ret |= jwin_hexedit_proc(msg, d, c);
4227 break;
4228 case nswapLDEC:
4229 d->d1 = 11; //11 digits max (incl '-')
4230 ret |= jwin_numedit_proc(msg, d, c);
4231 break;
4232 case nswapLHEX:
4233 d->d1 = 9; //9 digits max (incl '-')
4234 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
4235 c = (c&~255) | (toupper(c&255));
4236 ret |= jwin_hexedit_proc(msg, d, c);
4237 break;
4238 }
4239 if(rev_d2 && ref_d2 == d->d2)
4240 {
4241 d->d2 = old_d2;
4242 }
4243
4244 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
4245
4246 if(msg==MSG_START)
4247 tf_obj->refresh_cb_swap();
4248
4249 return ret;
4250 }
4251 int32_t jwin_numedit_noswap_zsint_proc(int32_t msg, DIALOG *d, int32_t c)
4252 {
4253 const size_t maxlen = 13;
4254 ASSERT(d->flags&D_NEW_GUI);
4255 GUI::TextField *tf_obj = (GUI::TextField*)d->dp3;
4256 if(!tf_obj) return D_O_K;
4257 int32_t ret = D_O_K;
4258 int32_t type = tf_obj->getSwapType();
4259
4260 char* str = (char*)d->dp;
4261 int64_t v = 0;
4262 if(msg == MSG_START)
4263 v = d->fg;
4264 else switch(type)
4265 {
4266 case nswapDEC:
4267 if(char *ptr = strchr(str, '.'))
4268 {
4269 char tempstr[32] = {0};
4270 strcpy(tempstr, str);
4271 for(int32_t q = 0; q < 4; ++q)
4272 tempstr[strlen(str)+q]='0';
4273 ptr = strchr(tempstr, '.');
4274 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
4275 v = atoi(tempstr);
4276 v *= 10000;
4277 if(tempstr[0] == '-')
4278 v -= atoi(ptr);
4279 else v += atoi(ptr);
4280 }
4281 else
4282 {
4283 v = atoi(str);
4284 v *= 10000;
4285 }
4286 break;
4287 case nswapHEX:
4288 if(char *ptr = strchr(str, '.'))
4289 {
4290 char tempstr[32] = {0};
4291 strcpy(tempstr, str);
4292 for(int32_t q = 0; q < 4; ++q)
4293 tempstr[strlen(str)+q]='0';
4294 ptr = strchr(tempstr, '.');
4295 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
4296 v = zc_xtoi(tempstr);
4297 v *= 10000;
4298 if(tempstr[0] == '-')
4299 v -= atoi(ptr);
4300 else v += atoi(ptr);
4301 }
4302 else
4303 {
4304 v = zc_xtoi(str);
4305 v *= 10000;
4306 }
4307 break;
4308 case nswapLDEC:
4309 v = zc_atoi64(str);
4310 break;
4311 case nswapLHEX:
4312 v = zc_xtoi64(str);
4313 break;
4314 case nswapBOOL:
4315 v = d->fg;
4316 break;
4317 }
4318 int32_t b;
4319 if ( v > 2147483647 )
4320 b=2147483647;
4321 else if ( v < INT_MIN )
4322 b=INT_MIN;
4323 else b = (int32_t)v;
4324 bool queued_neg = d->bg;
4325 if(msg==MSG_CHAR && ((c&255)=='-'))
4326 {
4327 if(b)
4328 {
4329 if(b==INT_MIN)
4330 ++b;
4331 b = -b;
4332 v = b;
4333 if(b<0)
4334 {
4335 if(str[0] != '-')
4336 {
4337 char buf[16] = {0};
4338 strcpy(buf, str);
4339 sprintf(str, "-%s", buf);
4340 INC_TF_CURSORS(d->d2,1,strlen(str));
4341 }
4342 }
4343 else if(str[0] == '-')
4344 {
4345 char buf[16] = {0};
4346 strcpy(buf, str);
4347 sprintf(str, "%s", buf+1);
4348 INC_TF_CURSORS(d->d2,-1,strlen(str));
4349 }
4350 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4351 }
4352 else queued_neg = !queued_neg; //queue negative
4353 c &= ~255;
4354 ret |= D_USED_CHAR;
4355 }
4356 if(b && queued_neg)
4357 {
4358 //b = -b; //actually, 'atoi' handles it for us.....
4359 queued_neg = false;
4360 }
4361 if(bool(d->bg) != queued_neg)
4362 {
4363 d->bg = queued_neg;
4364 if(queued_neg)
4365 {
4366 if(str[0] != '-')
4367 {
4368 char buf[16] = {0};
4369 strcpy(buf, str);
4370 sprintf(str, "-%s", buf);
4371 INC_TF_CURSORS(d->d2,1,strlen(str));
4372 }
4373 }
4374 else if(!b && str[0] == '-')
4375 {
4376 char buf[16] = {0};
4377 strcpy(buf, str);
4378 sprintf(str, "%s", buf+1);
4379 INC_TF_CURSORS(d->d2,-1,strlen(str));
4380 }
4381 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4382 }
4383 if(v != b || msg == MSG_START)
4384 {
4385 switch(type)
4386 {
4387 case nswapDEC:
4388 if(b < 0)
4389 sprintf(str, "-%ld.%04ld", abs(b/10000L), abs(b%10000L));
4390 else sprintf(str, "%ld.%04ld", b/10000L, b%10000L);
4391 trim_trailing_0s(str);
4392 break;
4393 case nswapHEX:
4394 if(b<0)
4395 sprintf(str, "-%lX.%04ld", abs(b/10000L), abs(b%10000L));
4396 else sprintf(str, "%lX.%04ld", b/10000L, abs(b%10000L));
4397 trim_trailing_0s(str);
4398 break;
4399 case nswapLDEC:
4400 sprintf(str, "%d", b);
4401 break;
4402 case nswapLHEX:
4403 if(b<0)
4404 sprintf(str, "-%X", -b);
4405 else sprintf(str, "%X", b);
4406 break;
4407 }
4408 d->d2 = 0xFFFF0000|strlen(str);
4409 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4410 }
4411 if(d->fg != b)
4412 {
4413 d->fg = b; //Store numeric data
4414 GUI_EVENT(d, geUPDATE_SWAP);
4415 }
4416 if(msg==MSG_CHAR && ((c&255)=='.'))
4417 {
4418 if(type >= nswapLDEC) //No '.' in long modes
4419 c&=~255;
4420 else
4421 {
4422 for(int32_t q = 0; str[q]; ++q)
4423 {
4424 if(str[q] == '.') //Only one '.'
4425 {
4426 c&=~255;
4427 break;
4428 }
4429 }
4430 }
4431 }
4432 bool rev_d2 = false;
4433 int32_t old_d2 = d->d2;
4434 int32_t ref_d2;
4435 if(msg == MSG_CHAR && queued_neg)
4436 {
4437 auto scursor = d->d2 & 0xFFFF;
4438 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
4439 if(!scursor)
4440 {
4441 rev_d2 = true;
4442 INC_TF_CURSORS(d->d2,1,strlen(str));
4443 ref_d2 = d->d2;
4444 }
4445 }
4446 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
4447 switch(type)
4448 {
4449 case nswapDEC:
4450 d->d1 = 12; //12 digits max (incl '-', '.')
4451 if(msg==MSG_CHAR && !editproc_special_key(c) && !areaselect)
4452 {
4453 int32_t p = 0;
4454 for(int32_t q = 0; str[q]; ++q)
4455 {
4456 if(str[q]=='.')
4457 {
4458 if((d->d2&0x0000FFFF) <= q)
4459 break; //typing before the '.'
4460 ++p;
4461 }
4462 else if(p) ++p;
4463 }
4464 if(p>=5) //too many chars after '.'
4465 c&=~255;
4466 }
4467 ret |= jwin_numedit_proc(msg, d, c);
4468 break;
4469 case nswapHEX:
4470 d->d1 = 11; //11 digits max (incl '-', '.')
4471 if(msg==MSG_CHAR && !editproc_special_key(c))
4472 {
4473 if(!((c&255)=='.'||isxdigit(c&255)))
4474 c&=~255;
4475 else if(isxdigit(c&255) && !isdigit(c&255))
4476 for(int32_t q = 0; q < (d->d2&0x0000FFFF) && str[q]; ++q)
4477 {
4478 if(str[q] == '.') //No hex digits to the right of the '.'
4479 {
4480 c&=~255;
4481 break;
4482 }
4483 }
4484 if((c&255) && !areaselect)
4485 {
4486 int32_t p = 0;
4487 for(int32_t q = 0; str[q]; ++q)
4488 {
4489 if(str[q]=='.')
4490 {
4491 if((d->d2&0x0000FFFF) <= q)
4492 break; //typing before the '.'
4493 ++p;
4494 }
4495 else if(p) ++p;
4496 }
4497 if(p>=5) //too many chars after '.'
4498 c&=~255;
4499 }
4500 if(isalpha(c&255)) //always capitalize
4501 c = (c&~255) | (toupper(c&255));
4502 }
4503 ret |= jwin_hexedit_proc(msg, d, c);
4504 break;
4505 case nswapLDEC:
4506 d->d1 = 11; //11 digits max (incl '-')
4507 ret |= jwin_numedit_proc(msg, d, c);
4508 break;
4509 case nswapLHEX:
4510 d->d1 = 9; //9 digits max (incl '-')
4511 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
4512 c = (c&~255) | (toupper(c&255));
4513 ret |= jwin_hexedit_proc(msg, d, c);
4514 break;
4515 }
4516 if(rev_d2 && ref_d2 == d->d2)
4517 {
4518 d->d2 = old_d2;
4519 }
4520
4521 if(msg==MSG_START)
4522 tf_obj->refresh_cb_swap();
4523
4524 return ret;
4525 }
4526
4527 /* _calc_scroll_bar:
4528 * Helps find positions of buttons on the scroll bar.
4529 */
4530 void _calc_scroll_bar(int32_t h, int32_t height, int32_t listsize, int32_t offset,
4531 int32_t *bh, int32_t *len, int32_t *pos)
4532 {
4533 *bh = zc_max(zc_min((h-4)/2, 14), 0);
4534 *len = zc_max(((h - 32) * height + listsize/2) / listsize , 6);
4535 *pos = ((h - 32 - *len) * offset) / (listsize-height);
4536 }
4537
4538 /* _handle_scrollable_click:
4539 * Helper to process a click on a scrollable object.
4540 */
4541
4542 void _handle_jwin_scrollable_scroll_click(DIALOG *d, int32_t listsize, int32_t *offset, FONT *fnt)
4543 {
4544 enum { top_btn, bottom_btn, bar, top_bar, bottom_bar };
4545
4546 int32_t xx, yy;
4547 int32_t height = (d->h-3) / (fnt ? text_height(fnt) : 1);
4548 int32_t hh = d->h - 32;
4549 int32_t obj = bar;
4550 int32_t bh, len, pos;
4551 int32_t down = 1, last_draw = 0;
4552 int32_t redraw = 0, mouse_delay = 0;
4553
4554 _calc_scroll_bar(d->h, height, listsize, *offset, &bh, &len, &pos);
4555
4556 xx = d->x + d->w - 18;
4557
4558 // find out which object is being clicked
4559
4560 yy = gui_mouse_y();
4561
4562 if(yy <= d->y+2+bh)
4563 {
4564 obj = top_btn;
4565 yy = d->y+2;
4566 }
4567 else if(yy >= d->y+d->h-2-bh)
4568 {
4569 obj = bottom_btn;
4570 yy = d->y+d->h-2-bh;
4571 }
4572 else if(d->h > 32+6)
4573 {
4574 if(yy < d->y+2+bh+pos)
4575 obj = top_bar;
4576 else if(yy >= d->y+2+bh+pos+len)
4577 obj = bottom_bar;
4578 }
4579
4580 while(gui_mouse_b())
4581 {
4582 _calc_scroll_bar(d->h, height, listsize, *offset, &bh, &len, &pos);
4583
4584 switch(obj)
4585 {
4586 case top_btn:
4587 case bottom_btn:
4588 down = mouse_in_rect(xx, yy, 16, bh);
4589
4590 if(!down)
4591 mouse_delay = 0;
4592 else
4593 {
4594 if((mouse_delay&1)==0)
4595 {
4596 if(obj==top_btn && *offset>0)
4597 {
4598 (*offset)--;
4599 redraw = 1;
4600 }
4601
4602 if(obj==bottom_btn && *offset<listsize-height)
4603 {
4604 (*offset)++;
4605 redraw = 1;
4606 }
4607 }
4608
4609 mouse_delay++;
4610 }
4611
4612 if(down!=last_draw || redraw)
4613 {
4614 vsync();
4615 d->proc(MSG_DRAW, d, 0);
4616 draw_arrow_button(screen, xx, yy, 16, bh, obj==top_btn, down*3);
4617 last_draw = down;
4618 }
4619
4620 break;
4621
4622 case top_bar:
4623 case bottom_bar:
4624 if(mouse_in_rect(xx, d->y+2, 16, d->h-4))
4625 {
4626 if(obj==top_bar)
4627 {
4628 if(gui_mouse_y() < d->y+2+bh+pos)
4629 yy = *offset - height;
4630 }
4631 else
4632 {
4633 if(gui_mouse_y() >= d->y+2+bh+pos+len)
4634 yy = *offset + height;
4635 }
4636
4637 if(yy < 0)
4638 yy = 0;
4639
4640 if(yy > listsize-height)
4641 yy = listsize-height;
4642
4643 if(yy != *offset)
4644 {
4645 *offset = yy;
4646 vsync();
4647 d->proc(MSG_DRAW, d, 0);
4648 }
4649 }
4650
4651 _calc_scroll_bar(d->h, height, listsize, *offset, &bh, &len, &pos);
4652
4653 if(!mouse_in_rect(xx, d->y+2+bh+pos, 16, len))
4654 break;
4655
4656 // fall through
4657
4658 case bar:
4659 default:
4660 xx = gui_mouse_y() - pos;
4661
4662 while(gui_mouse_b())
4663 {
4664 yy = (listsize * (gui_mouse_y() - xx) + hh/2) / hh;
4665
4666 if(yy > listsize-height)
4667 yy = listsize-height;
4668
4669 if(yy < 0)
4670 yy = 0;
4671
4672 bool should_redraw = false;
4673 if(yy != *offset)
4674 {
4675 *offset = yy;
4676 d->proc(MSG_DRAW, d, 0);
4677 should_redraw = true;
4678 }
4679
4680 /* let other objects continue to animate */
4681 int r = broadcast_dialog_message(MSG_IDLE, 0);
4682 if (r & D_REDRAWME) should_redraw = true;
4683
4684 if (should_redraw)
4685 {
4686 update_hw_screen();
4687 }
4688 }
4689
4690 break;
4691
4692 } // switch(obj)
4693
4694 redraw = 0;
4695
4696 update_hw_screen();
4697 // let other objects continue to animate
4698 broadcast_dialog_message(MSG_IDLE, 0);
4699 }
4700
4701 if(last_draw==1)
4702 {
4703 draw_arrow_button(screen, xx, yy, 16, bh, obj==top_btn, 0);
4704 }
4705 }
4706
4707 /* _handle_scrollable_scroll:
4708 * Helper function to scroll through a scrollable object.
4709 */
4710
4711 static void _handle_jwin_scrollable_scroll(DIALOG *d, int32_t listsize, int32_t *index, int32_t *offset, FONT *fnt)
4712 {
4713 int32_t height = (d->h-3) / text_height(fnt);
4714
4715 if(listsize <= 0)
4716 {
4717 *index = *offset = 0;
4718 return;
4719 }
4720
4721 // check selected item
4722 if(*index < 0)
4723 *index = 0;
4724 else if(*index >= listsize)
4725 *index = listsize - 1;
4726
4727 // check scroll position
4728 while((*offset > 0) && (*offset + height > listsize))
4729 (*offset)--;
4730
4731 if(*offset >= *index)
4732 {
4733 if(*index < 0)
4734 *offset = 0;
4735 else
4736 *offset = *index;
4737 }
4738 else
4739 {
4740 while((*offset + height - 1) < *index)
4741 (*offset)++;
4742 }
4743 }
4744
4745 /* idle_cb:
4746 * rest_callback() routine to keep dialogs animating nice and smoothly.
4747 */
4748
4749 static void idle_cb()
4750 {
4751 broadcast_dialog_message(MSG_IDLE, 0);
4752 }
4753
4754 /* _handle_listbox_click:
4755 * Helper to process a click on a listbox, doing hit-testing and moving
4756 * the selection.
4757 */
4758
4759 static bool _handle_jwin_listbox_click(DIALOG *d)
4760 {
4761 ListData *data = (ListData *)d->dp;
4762 char *sel = (char *)d->dp2;
4763 int32_t listsize, height;
4764 int32_t i, j;
4765
4766 data->listFunc(-1, &listsize);
4767
4768 if(!listsize)
4769 return false;
4770
4771 height = (d->h-3) / text_height(*data->font);
4772
4773 i = MID(0, ((gui_mouse_y() - d->y - 4) / text_height(*data->font)),
4774 ((d->h-3) / text_height(*data->font) - 1));
4775 i += d->d2;
4776
4777 if(i < d->d2)
4778 i = d->d2;
4779 else
4780 {
4781 if(i > d->d2 + height-1)
4782 i = d->d2 + height-1;
4783
4784 if(i >= listsize)
4785 i = listsize-1;
4786 }
4787
4788 if(gui_mouse_y() <= d->y)
4789 i = MAX(i-1, 0);
4790 else if(gui_mouse_y() >= d->y+d->h)
4791 i = MIN(i+1, listsize-1);
4792
4793 if(i != d->d1)
4794 {
4795 if(sel)
4796 {
4797 if(key_shifts & (KB_SHIFT_FLAG | KB_CTRL_FLAG))
4798 {
4799 if((key_shifts & KB_SHIFT_FLAG) || (d->flags & D_INTERNAL))
4800 {
4801 for(j=MIN(i, d->d1); j<=MAX(i, d->d1); j++)
4802 sel[j] = TRUE;
4803 }
4804 else
4805 sel[i] = TRUE;
4806 }
4807 }
4808
4809 d->d1 = i;
4810 i = d->d2;
4811
4812 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
4813
4814 object_message(d, MSG_DRAW, 0);
4815
4816 if(i != d->d2)
4817 rest_callback(MID(10, text_height(font)*16-d->h, 100), idle_cb);
4818 return true;
4819 }
4820 return false;
4821 }
4822
4823 /* _jwin_draw_scrollable_frame:
4824 * Helper function to draw a frame for all objects with vertical scrollbars.
4825 */
4826 void _jwin_draw_scrollable_frame(DIALOG *d, int32_t listsize, int32_t offset, int32_t height, int32_t type)
4827 {
4828 int32_t pos, len;
4829 int32_t xx, yy, hh, bh;
4830 static BITMAP *pattern = NULL; // just create it once
4831
4832 /* draw frame */
4833 if(type)
4834 // for droplists
4835 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DARK);
4836 else
4837 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DEEP);
4838
4839 /* possibly draw scrollbar */
4840 if(listsize > height)
4841 {
4842 _calc_scroll_bar(d->h, height, listsize, offset, &bh, &len, &pos);
4843
4844 xx = d->x + d->w - 18;
4845
4846 draw_arrow_button(screen, xx, d->y+2, 16, bh, 1, 0);
4847 draw_arrow_button(screen, xx, d->y+d->h-2-bh, 16, bh, 0, 0);
4848
4849 if(d->h > 32)
4850 {
4851 yy = d->y + 16;
4852 hh = (d->h-32);
4853
4854 /* create and draw the scrollbar */
4855 if(!pattern)
4856 pattern = create_bitmap_ex(bitmap_color_depth(screen),2,2);
4857
4858 putpixel(pattern, 0, 1, scheme[jcLIGHT]);
4859 putpixel(pattern, 1, 0, scheme[jcLIGHT]);
4860 putpixel(pattern, 0, 0, scheme[jcBOX]);
4861 putpixel(pattern, 1, 1, scheme[jcBOX]);
4862
4863 drawing_mode(DRAW_MODE_COPY_PATTERN, pattern, 0, 0);
4864 rectfill(screen, xx, yy, xx+15, yy+hh-1, 0);
4865 solid_mode();
4866
4867 if(d->h > 32+6)
4868 {
4869 jwin_draw_button(screen, xx, yy+pos, 16, len, 0, 1);
4870 }
4871 }
4872
4873 if(d->flags & D_GOTFOCUS)
4874 _dotted_rect(d->x+2, d->y+2, d->x+d->w-19, d->y+d->h-3, scheme[jcTEXTFG], scheme[jcTEXTBG]);
4875 }
4876 else if(d->flags & D_GOTFOCUS)
4877 _dotted_rect(d->x+2, d->y+2, d->x+d->w-3, d->y+d->h-3, scheme[jcTEXTFG], scheme[jcTEXTBG]);
4878 }
4879
4880 /*
4881 Effectively an overload of _jwin_draw_listbox that is used eclusively for file/abc listers.
4882 */
4883 void _jwin_draw_abclistbox(DIALOG *d)
4884 {
4885 int32_t height, listsize, i, len, bar, x, y, w;
4886 int32_t fg_color, bg_color, fg, bg;
4887 char *sel = (char*)d->dp2;
4888 char s[1024] = { 0 };
4889 ListData *data = (ListData *)d->dp;
4890
4891 FONT* oldfont = font;
4892 font = *data->font;
4893
4894 data->listFunc(-1, &listsize);
4895 height = (d->h-3) / text_height(font);
4896 bar = (listsize > height);
4897 w = (bar ? d->w-21 : d->w-5);
4898 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+d->h+9, scheme[jcBOX]);
4899 fg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : (d->fg ? d->fg : scheme[jcTEXTFG]);
4900 bg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_BG] : (d->bg ? d->bg : scheme[jcTEXTBG]);
4901
4902 rectfill(screen, d->x+2, d->y+2, d->x+w+2, d->y+3, bg_color);
4903 vline(screen, d->x+2, d->y+4, d->y+d->h-3, bg_color);
4904 vline(screen, d->x+3, d->y+4, d->y+d->h-3, bg_color);
4905 vline(screen, d->x+w+1, d->y+4, d->y+d->h-3, bg_color);
4906 vline(screen, d->x+w+2, d->y+4, d->y+d->h-3, bg_color);
4907 {
4908 rectfill(screen, d->x+1, d->y+d->h+2, d->x+d->w-2, d->y+1+d->h+text_height(font), bg_color);
4909 strncpy(s, abc_keypresses, 1023);
4910 char* s2 = s;
4911 int32_t tw = (d->w-1);
4912 while(text_length(font, s2) >= tw)
4913 {
4914 ++s2;
4915 }
4916 textout_ex(screen, font, s2, d->x+1, d->y+d->h+2,fg_color, bg_color);
4917 }
4918 //d->flags|=D_DIRTY;
4919
4920 /* draw box contents */
4921 for(i=0; i<height; i++)
4922 {
4923 if(d->d2+i < listsize)
4924 {
4925 if(d->d2+i == d->d1 && !(d->flags & D_DISABLED))
4926 {
4927 fg = scheme[jcSELFG];
4928 bg = scheme[jcSELBG];
4929 }
4930 else if((sel) && (sel[d->d2+i]))
4931 {
4932 fg = scheme[jcDISABLED_FG];
4933 bg = scheme[jcSELBG];
4934 }
4935 else
4936 {
4937 fg = fg_color;
4938 bg = bg_color;
4939 }
4940
4941 strncpy(s, data->listFunc(i+d->d2, NULL), 1023);
4942 x = d->x + 4;
4943 y = d->y + 4 + i*text_height(*data->font);
4944 // text_mode(bg);
4945 rectfill(screen, x, y, x+7, y+text_height(*data->font)-1, bg);
4946 x += 8;
4947 len = (int32_t)strlen(s);
4948
4949 while(text_length(*data->font, s) >= d->w - (bar ? 26 : 10))
4950 {
4951 len--;
4952 s[len] = 0;
4953 }
4954
4955 textout_ex(screen, *data->font, s, x, y, fg,bg);
4956 x += text_length(*data->font, s);
4957
4958 if(x <= d->x+w)
4959 rectfill(screen, x, y, d->x+w, y+text_height(*data->font)-1, bg);
4960 }
4961 else
4962 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
4963 d->x+w+2, d->y+3+(i+1)*text_height(*data->font), bg_color);
4964 }
4965
4966 if(d->y+4+i*text_height(font) <= d->y+d->h-3)
4967 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
4968 d->x+w+2, d->y+d->h-3, bg_color);
4969
4970 /* draw frame, maybe with scrollbar */
4971 _jwin_draw_scrollable_frame(d, listsize, d->d2, height, (d->flags&D_USER)?1:0);
4972
4973 font = oldfont;
4974 }
4975
4976 /* _jwin_draw_listbox:
4977 * Helper function to draw a listbox object.
4978 */
4979 void _jwin_draw_listbox(DIALOG *d)
4980 {
4981 int32_t height, listsize, i, len, bar, x, y, w;
4982 int32_t fg_color, bg_color, fg, bg;
4983 char *sel = (char*)d->dp2;
4984 char s[1024] = {0};
4985 ListData *data = (ListData *)d->dp;
4986
4987 data->listFunc(-1, &listsize);
4988 height = (d->h-3) / text_height(*data->font);
4989 bar = (listsize > height);
4990 w = (bar ? d->w-21 : d->w-5);
4991 fg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : (d->fg ? d->fg : scheme[jcTEXTFG]);
4992 bg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_BG] : (d->bg ? d->bg : scheme[jcTEXTBG]);
4993
4994 rectfill(screen, d->x+2, d->y+2, d->x+w+2, d->y+3, bg_color);
4995 vline(screen, d->x+2, d->y+4, d->y+d->h-3, bg_color);
4996 vline(screen, d->x+3, d->y+4, d->y+d->h-3, bg_color);
4997 vline(screen, d->x+w+1, d->y+4, d->y+d->h-3, bg_color);
4998 vline(screen, d->x+w+2, d->y+4, d->y+d->h-3, bg_color);
4999
5000 /* draw box contents */
5001 for(i=0; i<height; i++)
5002 {
5003 if(d->d2+i < listsize)
5004 {
5005 if(d->d2+i == d->d1 && !(d->flags & D_DISABLED))
5006 {
5007 fg = scheme[jcSELFG];
5008 bg = scheme[jcSELBG];
5009 }
5010 else if((sel) && (sel[d->d2+i]))
5011 {
5012 fg = scheme[jcMEDDARK];
5013 bg = scheme[jcSELBG];
5014 }
5015 else
5016 {
5017 fg = fg_color;
5018 bg = bg_color;
5019 }
5020
5021 strncpy(s, data->listFunc(i+d->d2, NULL), 1023);
5022 x = d->x + 4;
5023 y = d->y + 4 + i*text_height(*data->font);
5024 // text_mode(bg);
5025 rectfill(screen, x, y, x+7, y+text_height(*data->font)-1, bg);
5026 x += 8;
5027 len = (int32_t)strlen(s);
5028
5029 while(len > 0 && text_length(*data->font, s) >= d->w - (bar ? 26 : 10))
5030 {
5031 len--;
5032 s[len] = 0;
5033 }
5034
5035 textout_ex(screen, *data->font, s, x, y, fg,bg);
5036 x += text_length(*data->font, s);
5037
5038 if(x <= d->x+w)
5039 rectfill(screen, x, y, d->x+w, y+text_height(*data->font)-1, bg);
5040 }
5041 else
5042 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
5043 d->x+w+2, d->y+3+(i+1)*text_height(*data->font), bg_color);
5044 }
5045
5046 if(d->y+4+i*text_height(font) <= d->y+d->h-3)
5047 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
5048 d->x+w+2, d->y+d->h-3, bg_color);
5049
5050 /* draw frame, maybe with scrollbar */
5051 _jwin_draw_scrollable_frame(d, listsize, d->d2, height, (d->flags&D_USER)?1:0);
5052 }
5053
5054 /* jwin_list_proc:
5055 * A list box object. The dp field points to a ListData struct containing
5056 * a function which it will call
5057 * to obtain information about the list. This should follow the form:
5058 * char *<list_func_name> (int32_t index, int32_t *list_size);
5059 * If index is zero or positive, the function should return a pointer to
5060 * the string which is to be displayed at position index in the list. If
5061 * index is negative, it should return null and list_size should be set
5062 * to the number of items in the list. The list box object will allow the
5063 * user to scroll through the list and to select items list by clicking
5064 * on them, and if it has the input focus also by using the arrow keys. If
5065 * the D_EXIT flag is set, double clicking on a list item will cause it to
5066 * close the dialog. The index of the selected item is held in the d1
5067 * field, and d2 is used to store how far it has scrolled through the list.
5068 */
5069 int32_t jwin_list_proc(int32_t msg, DIALOG *d, int32_t c)
5070 {
5071 ListData *data = (ListData *)d->dp;
5072 int32_t listsize, i, bottom, height, bar, orig;
5073 char *sel = (char *)d->dp2;
5074 int32_t redraw = FALSE;
5075
5076 switch(msg)
5077 {
5078
5079 case MSG_START:
5080 data->listFunc(-1, &listsize);
5081 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5082 break;
5083
5084 case MSG_DRAW:
5085 _jwin_draw_listbox(d);
5086 break;
5087
5088 case MSG_CLICK:
5089 data->listFunc(-1, &listsize);
5090 height = (d->h-3) / text_height(*data->font);
5091 bar = (listsize > height);
5092
5093 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5094 {
5095 if((sel) && (!(key_shifts & KB_CTRL_FLAG)))
5096 {
5097 for(i=0; i<listsize; i++)
5098 {
5099 if(sel[i])
5100 {
5101 redraw = TRUE;
5102 sel[i] = FALSE;
5103 }
5104 }
5105
5106 if(redraw)
5107 {
5108 object_message(d, MSG_DRAW, 0);
5109 }
5110 }
5111
5112 if(_handle_jwin_listbox_click(d)) GUI_EVENT(d, geCHANGE_SELECTION);
5113
5114 bool rightClicked=(gui_mouse_b()&2)!=0;
5115 while(gui_mouse_b())
5116 {
5117 broadcast_dialog_message(MSG_IDLE, 0);
5118 d->flags |= D_INTERNAL;
5119 bool should_redraw = false;
5120 if(_handle_jwin_listbox_click(d))
5121 {
5122 d->flags &= ~D_INTERNAL;
5123 GUI_EVENT(d, geCHANGE_SELECTION);
5124 should_redraw = true;
5125 }
5126 d->flags &= ~D_INTERNAL;
5127
5128 /* let other objects continue to animate */
5129 int r = broadcast_dialog_message(MSG_IDLE, 0);
5130 if (r & D_REDRAWME) should_redraw = true;
5131
5132 if (should_redraw)
5133 {
5134 update_hw_screen();
5135 }
5136 }
5137
5138 if(rightClicked)
5139 {
5140 GUI_EVENT(d, geRCLICK);
5141 if((d->flags&(D_USER<<1))!=0 && d->dp3)
5142 {
5143 typedef void (*funcType)(int32_t /* index */, int32_t /* x */, int32_t /* y */);
5144 funcType func=reinterpret_cast<funcType>(d->dp3);
5145 func(d->d1, gui_mouse_x(), gui_mouse_y());
5146 }
5147 }
5148
5149 if(d->flags & D_USER)
5150 {
5151 if(listsize)
5152 {
5153 clear_keybuf();
5154 return D_CLOSE;
5155 }
5156 }
5157
5158 return D_REDRAWME;
5159 }
5160 else
5161 {
5162 _handle_jwin_scrollable_scroll_click(d, listsize, &d->d2, *data->font);
5163 }
5164
5165 break;
5166
5167 case MSG_DCLICK:
5168 // Ignore double right-click
5169 if((gui_mouse_b()&2)!=0)
5170 break;
5171
5172 data->listFunc(-1, &listsize);
5173 height = (d->h-3) / text_height(*data->font);
5174 bar = (listsize > height);
5175
5176 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5177 {
5178 if(listsize)
5179 {
5180 i = d->d1;
5181 object_message(d, MSG_CLICK, 0);
5182
5183 if(i == d->d1)
5184 {
5185 if(d->flags & D_EXIT)
5186 return D_CLOSE;
5187 else GUI_EVENT(d, geDCLICK);
5188 }
5189 }
5190 }
5191
5192 break;
5193
5194 case MSG_KEY:
5195 data->listFunc(-1, &listsize);
5196
5197 if((listsize) && (d->flags & D_EXIT))
5198 return D_CLOSE;
5199
5200 break;
5201
5202 case MSG_WANTFOCUS:
5203 return D_WANTFOCUS;
5204
5205 case MSG_WANTWHEEL:
5206 return 1;
5207
5208 case MSG_WHEEL:
5209 data->listFunc(-1, &listsize);
5210 height = (d->h-4) / text_height(*data->font);
5211
5212 if(height < listsize)
5213 {
5214 int32_t delta = (height > 3) ? 3 : 1;
5215
5216 if(c > 0)
5217 {
5218 i = MAX(0, d->d2-delta);
5219 }
5220 else
5221 {
5222 i = MIN(listsize-height, d->d2+delta);
5223 }
5224
5225 if(i != d->d2)
5226 {
5227 d->d2 = i;
5228 object_message(d, MSG_DRAW, 0);
5229 GUI_EVENT(d, geCHANGE_SELECTION);
5230 return D_REDRAWME;
5231 }
5232 }
5233
5234 break;
5235
5236 case MSG_CHAR:
5237 data->listFunc(-1,&listsize);
5238
5239 if(listsize)
5240 {
5241 c >>= 8;
5242
5243 bottom = d->d2 + (d->h-3)/text_height(*data->font) - 1;
5244
5245 if(bottom >= listsize-1)
5246 bottom = listsize-1;
5247
5248 orig = d->d1;
5249
5250 if(c == KEY_UP)
5251 d->d1--;
5252 else if(c == KEY_DOWN)
5253 d->d1++;
5254 else if(c == KEY_HOME)
5255 d->d1 = 0;
5256 else if(c == KEY_END)
5257 d->d1 = listsize-1;
5258 else if(c == KEY_PGUP)
5259 {
5260 if(d->d1 > d->d2)
5261 d->d1 = d->d2;
5262 else
5263 d->d1 -= (bottom - d->d2);
5264 }
5265 else if(c == KEY_PGDN)
5266 {
5267 if(d->d1 < bottom)
5268 d->d1 = bottom;
5269 else
5270 d->d1 += (bottom - d->d2);
5271 }
5272 else
5273 return D_O_K;
5274
5275 if(sel)
5276 {
5277 if(!(key_shifts & (KB_SHIFT_FLAG | KB_CTRL_FLAG)))
5278 {
5279 for(i=0; i<listsize; i++)
5280 sel[i] = FALSE;
5281 }
5282 else if(key_shifts & KB_SHIFT_FLAG)
5283 {
5284 for(i=MIN(orig, d->d1); i<=MAX(orig, d->d1); i++)
5285 {
5286 if(key_shifts & KB_CTRL_FLAG)
5287 sel[i] = (i != d->d1);
5288 else
5289 sel[i] = TRUE;
5290 }
5291 }
5292 }
5293
5294 /* if we changed something, better redraw... !Also bounds the index! */
5295 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5296
5297 GUI_EVENT(d, geCHANGE_SELECTION);
5298
5299 if (d->d1 != orig)
5300 d->flags |= D_DIRTY;
5301 return D_USED_CHAR;
5302 }
5303
5304 break;
5305 }
5306
5307 return D_O_K;
5308 }
5309
5310
5311 /*
5312 Effectively an overload of jwin_list_proc that i used eclusively for abc lists.
5313 This calls the appropriate form of drawing for those listers.
5314 */
5315 int32_t jwin_do_abclist_proc(int32_t msg, DIALOG *d, int32_t c)
5316 {
5317 ListData *data = (ListData *)d->dp;
5318 int32_t listsize, i, bottom, height, bar, orig, h;
5319 int32_t ret = D_O_K;
5320 bool revert_size = false;
5321 if((d->flags & D_RESIZED) == 0)
5322 {
5323 h = d->h;
5324 d->h -= text_height(*data->font);
5325 d->flags |= D_RESIZED;
5326 revert_size = true;
5327 }
5328 char *sel = (char *)d->dp2;
5329 int32_t redraw = FALSE;
5330
5331 switch(msg)
5332 {
5333
5334 case MSG_START:
5335 data->listFunc(-1, &listsize);
5336 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5337 break;
5338
5339 case MSG_DRAW:
5340 _jwin_draw_abclistbox(d);
5341 break;
5342
5343 case MSG_CLICK:
5344 if(gui_mouse_y() > (d->y+d->h-1))
5345 {
5346 if(gui_mouse_y() > (d->y+d->h+2))
5347 {
5348 //Clicked on the box displaying the patternmatch
5349 }
5350 else {} //Clicked between the lister and patternmatch
5351 }
5352 else //Clicked the lister
5353 {
5354 data->listFunc(-1, &listsize);
5355 height = (d->h-3) / text_height(*data->font);
5356 bar = (listsize > height);
5357
5358 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5359 {
5360 if((sel) && (!(key_shifts & KB_CTRL_FLAG)))
5361 {
5362 for(i=0; i<listsize; i++)
5363 {
5364 if(sel[i])
5365 {
5366 redraw = TRUE;
5367 sel[i] = FALSE;
5368 }
5369 }
5370
5371 if(redraw)
5372 {
5373 object_message(d, MSG_DRAW, 0);
5374 }
5375 }
5376
5377 if(_handle_jwin_listbox_click(d)) GUI_EVENT(d, geCHANGE_SELECTION);
5378
5379 bool rightClicked=(gui_mouse_b()&2)!=0;
5380 while(gui_mouse_b())
5381 {
5382 broadcast_dialog_message(MSG_IDLE, 0);
5383 d->flags |= D_INTERNAL;
5384 if(_handle_jwin_listbox_click(d))
5385 {
5386 d->flags &= ~D_INTERNAL;
5387 GUI_EVENT(d, geCHANGE_SELECTION);
5388 update_hw_screen();
5389 }
5390 d->flags &= ~D_INTERNAL;
5391 rest(1);
5392 }
5393
5394 if(rightClicked)
5395 {
5396 GUI_EVENT(d, geRCLICK);
5397 if((d->flags&(D_USER<<1))!=0 && d->dp3)
5398 {
5399 typedef void (*funcType)(int32_t /* index */, int32_t /* x */, int32_t /* y */);
5400 funcType func=reinterpret_cast<funcType>(d->dp3);
5401 func(d->d1, gui_mouse_x(), gui_mouse_y());
5402 }
5403 }
5404
5405 if(d->flags & D_USER)
5406 {
5407 if(listsize)
5408 {
5409 clear_keybuf();
5410 ret = D_CLOSE;
5411 }
5412 }
5413
5414 return D_REDRAWME;
5415 }
5416 else
5417 {
5418 _handle_jwin_scrollable_scroll_click(d, listsize, &d->d2, *data->font);
5419 }
5420 }
5421 break;
5422
5423 case MSG_DCLICK:
5424 // Ignore double right-click
5425 if((gui_mouse_b()&2)!=0)
5426 break;
5427
5428 if(gui_mouse_y() > (d->y+d->h-1))
5429 {
5430 if(gui_mouse_y() > (d->y+d->h+2))
5431 {
5432 //Clicked on the box displaying the patternmatch
5433 }
5434 else {} //Clicked between the lister and patternmatch
5435 }
5436 else //Clicked the lister
5437 {
5438 data->listFunc(-1, &listsize);
5439 height = (d->h-3) / text_height(*data->font);
5440 bar = (listsize > height);
5441
5442 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5443 {
5444 if(listsize)
5445 {
5446 i = d->d1;
5447 object_message(d, MSG_CLICK, 0);
5448
5449 if(i == d->d1)
5450 {
5451 if(d->flags & D_EXIT)
5452 ret = D_CLOSE;
5453 else GUI_EVENT(d, geDCLICK);
5454 }
5455 }
5456 }
5457 }
5458 break;
5459
5460 case MSG_KEY:
5461 data->listFunc(-1, &listsize);
5462
5463 if((listsize) && (d->flags & D_EXIT))
5464 ret = D_CLOSE;
5465
5466 break;
5467
5468 case MSG_WANTFOCUS:
5469 ret = D_WANTFOCUS;
5470 break;
5471
5472 case MSG_WANTWHEEL:
5473 return 1;
5474
5475 case MSG_WHEEL:
5476 data->listFunc(-1, &listsize);
5477 height = (d->h-4) / text_height(*data->font);
5478
5479 if(height < listsize)
5480 {
5481 int32_t delta = (height > 3) ? 3 : 1;
5482
5483 if(c > 0)
5484 {
5485 i = MAX(0, d->d2-delta);
5486 }
5487 else
5488 {
5489 i = MIN(listsize-height, d->d2+delta);
5490 }
5491
5492 if(i != d->d2)
5493 {
5494 d->d2 = i;
5495 object_message(d, MSG_DRAW, 0);
5496 GUI_EVENT(d, geCHANGE_SELECTION);
5497 ret |= D_REDRAWME;
5498 }
5499 }
5500
5501 break;
5502
5503 case MSG_CHAR:
5504 data->listFunc(-1,&listsize);
5505
5506 if(listsize)
5507 {
5508 c >>= 8;
5509
5510 bottom = d->d2 + (d->h-3)/text_height(*data->font) - 1;
5511
5512 if(bottom >= listsize-1)
5513 bottom = listsize-1;
5514
5515 orig = d->d1;
5516
5517 if(c == KEY_UP)
5518 d->d1--;
5519 else if(c == KEY_DOWN)
5520 d->d1++;
5521 else if(c == KEY_HOME)
5522 d->d1 = 0;
5523 else if(c == KEY_END)
5524 d->d1 = listsize-1;
5525 else if(c == KEY_PGUP)
5526 {
5527 if(d->d1 > d->d2)
5528 d->d1 = d->d2;
5529 else
5530 d->d1 -= (bottom - d->d2);
5531 }
5532 else if(c == KEY_PGDN)
5533 {
5534 if(d->d1 < bottom)
5535 d->d1 = bottom;
5536 else
5537 d->d1 += (bottom - d->d2);
5538 }
5539 else
5540 break; //return D_O_K;
5541
5542 if(sel)
5543 {
5544 if(!(key_shifts & (KB_SHIFT_FLAG | KB_CTRL_FLAG)))
5545 {
5546 for(i=0; i<listsize; i++)
5547 sel[i] = FALSE;
5548 }
5549 else if(key_shifts & KB_SHIFT_FLAG)
5550 {
5551 for(i=MIN(orig, d->d1); i<=MAX(orig, d->d1); i++)
5552 {
5553 if(key_shifts & KB_CTRL_FLAG)
5554 sel[i] = (i != d->d1);
5555 else
5556 sel[i] = TRUE;
5557 }
5558 }
5559 }
5560
5561 /* if we changed something, better redraw... */
5562 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5563
5564 GUI_EVENT(d, geCHANGE_SELECTION);
5565
5566 if (d->d1 != orig)
5567 d->flags |= D_DIRTY;
5568 ret = D_USED_CHAR;
5569 }
5570
5571 break;
5572 }
5573 if(revert_size)
5574 {
5575 d->h = h;
5576 d->flags &= ~D_RESIZED;
5577 }
5578 return ret;
5579 }
5580
5581 /* _jwin_draw_textbox:
5582 * Helper function to draw a textbox object.
5583 */
5584 void _jwin_draw_textbox(char *thetext, int32_t *listsize, int32_t draw, int32_t offset,
5585 int32_t wword, int32_t tabsize, int32_t x, int32_t y, int32_t w, int32_t h,
5586 int32_t disabled)
5587 {
5588 int32_t fg = scheme[jcTEXTFG];
5589 int32_t bg = scheme[jcTEXTBG];
5590 int32_t y1 = y+4;
5591 int32_t x1;
5592 int32_t len;
5593 int32_t ww = w-10;
5594 char s[16] = {0};
5595 char text[16] = {0};
5596 char space[16] = {0};
5597 char *printed = text;
5598 char *scanned = text;
5599 char *oldscan = text;
5600 char *ignore = NULL;
5601 char *tmp, *ptmp;
5602 int32_t width;
5603 int32_t line = 0;
5604 int32_t i = 0;
5605 int32_t noignore;
5606 // int32_t rtm;
5607
5608 usetc(s+usetc(s, '.'), 0);
5609 usetc(text+usetc(text, ' '), 0);
5610 usetc(space+usetc(space, ' '), 0);
5611
5612 /* find the correct text */
5613 if(thetext != NULL)
5614 {
5615 printed = thetext;
5616 scanned = thetext;
5617 }
5618
5619 /* choose the text color */
5620 if(disabled)
5621 {
5622 fg = scheme[jcDISABLED_FG];
5623 bg = scheme[jcDISABLED_BG];
5624 }
5625
5626 /* do some drawing setup */
5627 if(draw)
5628 {
5629 /* initial start blanking at the top */
5630 rectfill(screen, x+2, y+2, x+w-2, y1-1, bg);
5631 }
5632
5633 // rtm = text_mode(bg);
5634
5635 /* loop over the entire string */
5636 for(;;)
5637 {
5638 width = 0;
5639
5640 /* find the next break */
5641 while(ugetc(scanned))
5642 {
5643 /* check for a forced break */
5644 if(ugetc(scanned) == '\n')
5645 {
5646 scanned += uwidth(scanned);
5647
5648 /* we are done parsing the line end */
5649 break;
5650 }
5651
5652 /* the next character length */
5653 usetc(s+usetc(s, ugetc(scanned)), 0);
5654 len = text_length(font, s);
5655
5656 /* modify length if its a tab */
5657 if(ugetc(s) == '\t')
5658 len = tabsize * text_length(font, space);
5659
5660 /* check for the end of a line by excess width of next char */
5661 if(width+len >= ww)
5662 {
5663 /* we have reached end of line do we go back to find start */
5664 if(wword)
5665 {
5666 /* remember where we were */
5667 oldscan = scanned;
5668 noignore = FALSE;
5669
5670 /* go backwards looking for start of word */
5671 while(!uisspace(ugetc(scanned)))
5672 {
5673 /* don't wrap too far */
5674 if(scanned == printed)
5675 {
5676 /* the whole line is filled, so stop here */
5677 tmp = ptmp = scanned;
5678
5679 while(ptmp != oldscan)
5680 {
5681 ptmp = tmp;
5682 tmp += uwidth(tmp);
5683 }
5684
5685 scanned = ptmp;
5686 noignore = TRUE;
5687 break;
5688 }
5689
5690 /* look further backwards to wrap */
5691 tmp = ptmp = printed;
5692
5693 while(tmp < scanned)
5694 {
5695 ptmp = tmp;
5696 tmp += uwidth(tmp);
5697 }
5698
5699 scanned = ptmp;
5700 }
5701
5702 /* put the space at the end of the line */
5703 if(!noignore)
5704 {
5705 ignore = scanned;
5706 scanned += uwidth(scanned);
5707 }
5708 else
5709 ignore = NULL;
5710
5711 /* check for endline at the convenient place */
5712 if(ugetc(scanned) == '\n')
5713 scanned += uwidth(scanned);
5714 }
5715
5716 /* we are done parsing the line end */
5717 break;
5718 }
5719
5720 /* the character can be added */
5721 scanned += uwidth(scanned);
5722 width += len;
5723 }
5724
5725 /* check if we are to print it */
5726 if((draw) && (line >= offset) && (y1+text_height(font) < (y+h-3)))
5727 {
5728 x1 = x+4;
5729
5730 /* the initial blank bit */
5731 rectfill(screen, x+2, y1, x1-1, y1+text_height(font), bg);
5732
5733 /* print up to the marked character */
5734 while(printed != scanned)
5735 {
5736 /* do special stuff for each character */
5737 switch(ugetc(printed))
5738 {
5739
5740 case '\r':
5741 case '\n':
5742 /* don't print endlines in the text */
5743 break;
5744
5745 /* possibly expand the tabs */
5746 case '\t':
5747 for(i=0; i<tabsize; i++)
5748 {
5749 usetc(s+usetc(s, ' '), 0);
5750 textout_ex(screen, font, s, x1, y1, fg,bg);
5751 x1 += text_length(font, s);
5752 }
5753
5754 break;
5755
5756 /* print a normal character */
5757 default:
5758 if(printed != ignore)
5759 {
5760 usetc(s+usetc(s, ugetc(printed)), 0);
5761 textout_ex(screen, font, s, x1, y1, fg,bg);
5762 x1 += text_length(font, s);
5763 }
5764 }
5765
5766 /* goto the next character */
5767 printed += uwidth(printed);
5768 }
5769
5770 /* the last blank bit */
5771 if(x1 <= x+w-3)
5772 rectfill(screen, x1, y1, x+w-2, y1+text_height(font)-1, bg);
5773
5774 /* print the line end */
5775 y1 += text_height(font);
5776 }
5777
5778 printed = scanned;
5779
5780 /* we have done a line */
5781 line++;
5782
5783 /* check if we are at the end of the string */
5784 if(!ugetc(printed))
5785 {
5786 /* the under blank bit */
5787 if(draw)
5788 rectfill(screen, x+1, y1, x+w-2, y+h-1, bg);
5789
5790 /* tell how many lines we found */
5791 *listsize = line;
5792 // text_mode(rtm);
5793 return;
5794 }
5795 }
5796
5797 // text_mode(rtm);
5798 }
5799
5800 /* jwin_textbox_proc:
5801 * A text box object. The dp field points to a char * which is the text
5802 * to be displayed in the text box. If the text is long, there will be
5803 * a vertical scrollbar on the right hand side of the object which can
5804 * be used to scroll through the text. The default is to print the text
5805 * with word wrapping, but if the D_SELECTED flag is set, the text will
5806 * be printed with character wrapping. The d1 field is used internally
5807 * to store the number of lines of text, and d2 is used to store how far
5808 * it has scrolled through the text.
5809 */
5810 int32_t jwin_textbox_proc(int32_t msg, DIALOG *d, int32_t c)
5811 {
5812 int32_t height, bar, ret = D_O_K;
5813 int32_t start, top, bottom,l;
5814 int32_t used, delta;
5815 // int32_t fg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
5816
5817 FONT *oldfont=NULL;
5818
5819 if(d->dp2!=NULL)
5820 {
5821 oldfont=font;
5822 font=(FONT*)d->dp2;
5823 }
5824
5825 /* calculate the actual height */
5826 height = (d->h-4) / text_height(font);
5827
5828 switch(msg)
5829 {
5830
5831 case MSG_START:
5832 /* measure how many lines of text we contain */
5833 _jwin_draw_textbox((char*)d->dp, &d->d1,
5834 0, /* DONT DRAW anything */
5835 d->d2, !(d->flags & D_SELECTED), 8,
5836 d->x, d->y, d->w, d->h,
5837 (d->flags & D_DISABLED));
5838 break;
5839
5840 case MSG_DRAW:
5841 /* tell the object to sort of draw, but only calculate the listsize */
5842 _jwin_draw_textbox((char*)d->dp, &d->d1,
5843 0, /* DONT DRAW anything */
5844 d->d2, !(d->flags & D_SELECTED), 8,
5845 d->x, d->y, d->w, d->h,
5846 (d->flags & D_DISABLED));
5847
5848 if(d->d1 > height)
5849 {
5850 bar = 16;
5851 }
5852 else
5853 {
5854 bar = 0;
5855 d->d2 = 0;
5856 }
5857
5858 /* now do the actual drawing */
5859 _jwin_draw_textbox((char*)d->dp, &d->d1, 1, d->d2,
5860 !(d->flags & D_SELECTED), 8,
5861 d->x, d->y, d->w-bar-1, d->h,
5862 (d->flags & D_DISABLED));
5863
5864 /* draw the frame around */
5865 _jwin_draw_scrollable_frame(d, d->d1, d->d2, height, 0);
5866 break;
5867
5868 case MSG_CLICK:
5869 /* figure out if it's on the text or the scrollbar */
5870 bar = (d->d1 > height);
5871
5872 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5873 {
5874 /* clicked on the text area */
5875 ret = D_O_K;
5876 }
5877 else
5878 {
5879 /* clicked on the scroll area */
5880 _handle_jwin_scrollable_scroll_click(d, d->d1, &d->d2, font);
5881 }
5882
5883 break;
5884
5885 case MSG_WANTWHEEL:
5886 return 1;
5887
5888 case MSG_WHEEL:
5889 l = (d->h-8)/text_height(font);
5890 delta = (l > 3) ? 3 : 1;
5891
5892 // scroll, making sure that the list stays in bounds
5893 start = d->d2;
5894 d->d2 = (c > 0) ? MAX(0, d->d2-delta) : MIN(d->d1-l, d->d2+delta);
5895
5896 // if we changed something, better redraw...
5897 if(d->d2 != start)
5898 {
5899 d->flags |= D_DIRTY;
5900 }
5901
5902 ret = D_O_K;
5903 break;
5904
5905 case MSG_CHAR:
5906 start = d->d2;
5907 used = D_USED_CHAR;
5908
5909 if(d->d1 > 0)
5910 {
5911 if(d->d2 > 0)
5912 top = d->d2+1;
5913 else
5914 top = 0;
5915
5916 l = (d->h-3)/text_height(font);
5917
5918 bottom = d->d2 + l - 1;
5919
5920 if(bottom >= d->d1-1)
5921 bottom = d->d1-1;
5922 else
5923 bottom--;
5924
5925 if((c>>8) == KEY_UP)
5926 d->d2--;
5927 else if((c>>8) == KEY_DOWN)
5928 d->d2++;
5929 else if((c>>8) == KEY_HOME)
5930 d->d2 = 0;
5931 else if((c>>8) == KEY_END)
5932 d->d2 = d->d1-l;
5933 else if((c>>8) == KEY_PGUP)
5934 d->d2 = d->d2-(bottom-top);
5935 else if((c>>8) == KEY_PGDN)
5936 d->d2 = d->d2+(bottom-top);
5937 else
5938 used = D_O_K;
5939
5940 /* make sure that the list stays in bounds */
5941 if(d->d2 > d->d1-l)
5942 d->d2 = d->d1-l;
5943
5944 if(d->d2 < 0)
5945 d->d2 = 0;
5946 }
5947 else
5948 used = D_O_K;
5949
5950 /* if we changed something, better redraw... */
5951 if(d->d2 != start)
5952 {
5953 d->proc(MSG_DRAW, d, 0);
5954 }
5955
5956 ret = used;
5957 break;
5958
5959 case MSG_WANTFOCUS:
5960
5961 /* if we don't have a scrollbar we can't do anything with the focus */
5962 if(d->d1 > height)
5963 ret = D_WANTFOCUS;
5964
5965 break;
5966
5967 default:
5968 ret = D_O_K;
5969 }
5970
5971 if(d->dp2!=NULL)
5972 {
5973 font=oldfont;
5974 }
5975
5976 return ret;
5977 }
5978
5979 /* jwin_slider_proc:
5980 * A slider control object. This object returns a value in d2, in the
5981 * range from 0 to d1. It will display as a vertical slider if h is
5982 * greater than or equal to w; otherwise, it will display as a horizontal
5983 * slider. dp can contain an optional bitmap to use for the slider handle;
5984 * dp2 can contain an optional callback function, which is called each
5985 * time d2 changes. The callback function should have the following
5986 * prototype:
5987 *
5988 * int32_t function(void *dp3, int32_t d2);
5989 *
5990 * The d_slider_proc object will return the value of the callback function.
5991 */
5992 int32_t jwin_slider_proc(int32_t msg, DIALOG *d, int32_t c)
5993 {
5994 BITMAP *slhan = NULL;
5995 int32_t sfg; /* slider foreground color */
5996 int32_t vert = TRUE; /* flag: is slider vertical? */
5997 int32_t hh = 7; /* handle height (width for horizontal sliders) */
5998 int32_t hmar; /* handle margin */
5999 int32_t slp; /* slider position */
6000 int32_t irange;
6001 int32_t slx, sly, slh, slw;
6002 fixed slratio, slmax, slpos;
6003 ASSERT(d);
6004
6005 /* check for slider direction */
6006 if(d->h < d->w)
6007 {
6008 vert = FALSE;
6009 }
6010
6011 /* set up the metrics for the control */
6012 if(d->dp != NULL)
6013 {
6014 slhan = (BITMAP *)d->dp;
6015
6016 if(vert)
6017 {
6018 hh = slhan->h;
6019 }
6020 else
6021 {
6022 hh = slhan->w;
6023 }
6024 }
6025
6026 hmar = hh/2;
6027 irange = (vert) ? d->h : d->w;
6028 slmax = itofix(irange-hh);
6029 slratio = slmax / (d->d1);
6030 slpos = slratio * d->d2;
6031 slp = fixtoi(slpos);
6032
6033 switch(msg)
6034 {
6035 case MSG_DRAW:
6036 // sfg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : scheme[jcBOXFG];
6037 sfg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : scheme[jcBOXFG];
6038
6039 if(vert)
6040 {
6041 rectfill(screen, d->x, d->y, d->x+d->w/2-2, d->y+d->h, scheme[jcBOX]);
6042 rectfill(screen, d->x+d->w/2-1, d->y, d->x+d->w/2+1, d->y+d->h, sfg);
6043 rectfill(screen, d->x+d->w/2+2, d->y, d->x+d->w, d->y+d->h, scheme[jcBOX]);
6044 }
6045 else
6046 {
6047 rectfill(screen, d->x, d->y, d->x+d->w, d->y+d->h/2-2, scheme[jcBOX]);
6048 rectfill(screen, d->x, d->y+d->h/2-1, d->x+d->w, d->y+d->h/2+1, sfg);
6049 rectfill(screen, d->x, d->y+d->h/2+2, d->x+d->w, d->y+d->h, scheme[jcBOX]);
6050 }
6051
6052 if(d->flags & D_GOTFOCUS)
6053 {
6054 _dotted_rect(d->x, d->y, d->x+d->w, d->y+d->h, sfg, scheme[jcBOX]);
6055 }
6056
6057 /* okay, background and slot are drawn, now draw the handle */
6058 if(slhan)
6059 {
6060 if(vert)
6061 {
6062 slx = d->x+(d->w/2)-(slhan->w/2);
6063 sly = d->y+d->h-(hh+slp);
6064 }
6065 else
6066 {
6067 slx = d->x+slp;
6068 sly = d->y+(d->h/2)-(slhan->h/2);
6069 }
6070
6071 draw_sprite(screen, slhan, slx, sly);
6072 }
6073 else
6074 {
6075 /* draw default handle */
6076 if(vert)
6077 {
6078 slx = d->x;
6079 sly = d->y+d->h-(hh+slp);
6080 slw = d->w;
6081 slh = hh;
6082 }
6083 else
6084 {
6085 slx = d->x+slp;
6086 sly = d->y;
6087 slw = hh;
6088 slh = d->h;
6089 }
6090
6091 jwin_draw_button(screen, slx, sly, slw+1, slh+1, d->flags&D_DISABLED?3:0, 0);
6092 }
6093
6094 break;
6095
6096 default:
6097 return d_jslider_proc(msg, d, c);
6098 }
6099
6100 return D_O_K;
6101 }
6102
6103 const char* rowpref(int32_t row, bool alt)
6104 {
6105 static const char *lcol = "Level Colors", *syscol = "System Colors", *bosscol = "Boss Colors", *thmcol = "Theme Colors", *nlcol="";
6106 switch(row)
6107 {
6108 case 2: case 3: case 4: case 9:
6109 return lcol;
6110 case 14:
6111 return alt ? syscol : bosscol;
6112 case 15:
6113 return thmcol;
6114 default:
6115 return nlcol;
6116 }
6117 }
6118
6119 byte getHighlightColor(int32_t c)
6120 {
6121 RGB col;
6122 get_color(c, &col);
6123 return getHighlightColor(col);
6124 }
6125
6126 byte getHighlightColor(RGB const& col)
6127 {
6128 double lum = (pow(col.r/64.0, 2.2) * 0.2126) +
6129 (pow(col.g/64.0, 2.2) * 0.7152) +
6130 (pow(col.b/64.0, 2.2) * 0.0722);
6131 return lum < 0.4 ? vc(15) : vc(0);
6132 //Old -Em
6133 // byte bright = (col.r >= 32) + (col.g >= 32) + (col.b >= 32);
6134 // byte sbright = (col.r >= 48) + (col.g >= 48) + (col.b >= 48);
6135 // byte highlightColor = vc(7); //sysgray
6136 // if(bright >= 2)
6137 // {
6138 // if(sbright >= 2)
6139 // highlightColor = vc(0); //sysblack
6140 // else highlightColor = vc(8); //sysdarkgray
6141 // }
6142 // else if(!bright)
6143 // highlightColor = vc(15); //syswhite
6144 // return highlightColor;
6145 }
6146
6147 int32_t jwin_selcolor_proc(int32_t msg, DIALOG *d, int32_t c)
6148 {
6149 int32_t ret = D_O_K;
6150 if(!d->d2) d->d2 = 12;
6151 bool alt = d->d2 > 16;
6152 int32_t numcsets = alt ? 16 : d->d2;
6153 int32_t numcol = numcsets*0x10;
6154 if(msg==MSG_START)
6155 {
6156 d->w = d->h = (16*8) * 1.5;
6157 }
6158 int32_t csz = 12;
6159 d->w = csz * 16;
6160 d->h = csz * numcsets;
6161 switch(msg)
6162 {
6163 case MSG_DRAW:
6164 {
6165 jwin_draw_frame(screen, d->x-2, d->y-2, d->w+4, d->h+4, FR_ETCHED);
6166 for(int32_t c = 0; c < numcol; ++c)
6167 {
6168 int32_t x = (c%16)*csz, y = (c/16)*csz;
6169 rectfill(screen, d->x+x, d->y+y, d->x+x+csz-1, d->y+y+csz-1, c);
6170 if(c == d->d1)
6171 {
6172 byte highlightColor = getHighlightColor(c);
6173 rect(screen, d->x+x+0, d->y+y+0, d->x+x+csz-1, d->y+y+csz-1, highlightColor);
6174 rect(screen, d->x+x+1, d->y+y+1, d->x+x+csz-2, d->y+y+csz-2, highlightColor);
6175 }
6176 }
6177
6178 FONT *oldfont = font;
6179
6180 if(d->dp2)
6181 {
6182 font = (FONT*)d->dp2;
6183 }
6184
6185 char buf[32]={0};
6186 for(int32_t col = 0; col < 16; ++col)
6187 {
6188 sprintf(buf, "%X", col);
6189 gui_textout_ln(screen, (uint8_t*)buf, d->x + (csz*col) + (csz/2), d->y-3-text_height(font), scheme[jcBOXFG], scheme[jcBOX], 1);
6190 }
6191 for(int32_t row = 0; row < numcsets; ++row)
6192 {
6193 sprintf(buf, "%s 0x%02X", rowpref(row, alt), row*16);
6194 gui_textout_ln(screen, (uint8_t*)buf, d->x-3, d->y + (csz*row) + (csz-text_height(font))/2, scheme[jcBOXFG], scheme[jcBOX], 2);
6195 }
6196
6197 font = oldfont;
6198 break;
6199 }
6200
6201 case MSG_CLICK:
6202 {
6203 if(mouse_in_rect(d->x, d->y, d->x+d->w-1, d->y+d->h-1))
6204 {
6205 int32_t col = ((gui_mouse_x() - d->x) / csz) + 16*((gui_mouse_y() - d->y) / csz);
6206
6207 if(col>-1 && col != d->d1)
6208 {
6209 d->d1 = col;
6210 ret |= D_REDRAWME;
6211 }
6212 ret |= D_WANTFOCUS;
6213 }
6214 break;
6215 }
6216
6217 case MSG_WANTFOCUS:
6218 case MSG_LOSTFOCUS:
6219 case MSG_KEY:
6220 ret = D_WANTFOCUS;
6221 break;
6222
6223 case MSG_CHAR:
6224 {
6225 ret = D_USED_CHAR | D_REDRAWME;
6226 switch(c>>8)
6227 {
6228 case KEY_LEFT:
6229 {
6230 if(d->d1 % 0x10)
6231 --d->d1;
6232 break;
6233 }
6234 case KEY_RIGHT:
6235 {
6236 if(d->d1 % 0x10 != 0x0F)
6237 ++d->d1;
6238 break;
6239 }
6240 case KEY_UP:
6241 {
6242 if(d->d1 / 0x10)
6243 d->d1 -= 0x10;
6244 break;
6245 }
6246 case KEY_DOWN:
6247 {
6248 if(d->d1 / 0x10 != numcsets)
6249 d->d1 += 0x10;
6250 break;
6251 }
6252 case KEY_ENTER:
6253 {
6254 ret = D_CLOSE;
6255 break;
6256 }
6257 default: ret = D_O_K;
6258 }
6259 break;
6260 }
6261 }
6262 return ret;
6263 }
6264
6265 static DIALOG selcolor_dlg[] =
6266 {
6267 { jwin_win_proc, 0, 0, 306, 63+16*8, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *)"Select Color", NULL, NULL },
6268 { jwin_button_proc, 75, 40+16*8, 61, 21, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *)"OK", NULL, NULL },
6269 { jwin_button_proc, 164, 40+16*8, 61, 21, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *)"Cancel", NULL, NULL },
6270 { jwin_selcolor_proc, 156-64, 34, 16*8, 16*8, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6271
6272 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6273 };
6274
6275 int32_t jwin_color_swatch(int32_t msg, DIALOG *d, int32_t c)
6276 {
6277 int32_t ret = D_O_K;
6278
6279 switch(msg)
6280 {
6281 case MSG_START:
6282 {
6283 if(d->d2 < 1) d->d2 = 12;
6284 else if(d->d2 > 17) d->d2 = 17;
6285 break;
6286 }
6287
6288 case MSG_DRAW:
6289 {
6290 if(!d->d1 || (d->flags&D_DISABLED))
6291 {
6292 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1,
6293 (d->flags&D_DISABLED) ? scheme[jcDISABLED_BG] : vc(0));
6294 line(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1, vc(15));
6295 line(screen, d->x, d->y+d->h-1, d->x+d->w-1, d->y, vc(15));
6296 jwin_draw_frame(screen, d->x-2, d->y-2, d->w+4, d->h+4, FR_DEEP);
6297 }
6298 else
6299 {
6300 int32_t c;
6301 switch(d->d1) //special cases
6302 {
6303 case BLACK:
6304 c = vc(0);
6305 break;
6306 case WHITE:
6307 c = vc(15);
6308 break;
6309 default:
6310 c = d->d1;
6311 break;
6312 }
6313 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1, c);
6314 jwin_draw_frame(screen, d->x-2, d->y-2, d->w+4, d->h+4, FR_ETCHED);
6315 }
6316 break;
6317 }
6318
6319 case MSG_CLICK:
6320 {
6321 if(d->flags&(D_READONLY|D_DISABLED)) break;
6322 selcolor_dlg[0].dp2 = get_zc_font(font_lfont);
6323 selcolor_dlg[3].bg = scheme[jcBOXFG];
6324 selcolor_dlg[3].fg = scheme[jcBOX];
6325 selcolor_dlg[3].d1 = d->d1;
6326 selcolor_dlg[3].d2 = d->d2;
6327 large_dialog(selcolor_dlg);
6328
6329 while(gui_mouse_b()) rest(1); //wait for mouseup
6330
6331 //!TODO Move this out of jwin, and do better palette management.
6332 //!TODO Allow loading different level palettes, sprite palettes, etc via buttons
6333 PALETTE oldpal;
6334 get_palette(oldpal);
6335 bool alt = d->d2 > 16;
6336 if(!alt)
6337 {
6338 PALETTE foopal;
6339 get_palette(foopal);
6340 foopal[BLACK] = _RGB(0,0,0);
6341 foopal[WHITE] = _RGB(255,255,255);
6342 zc_set_palette(foopal);
6343 }
6344
6345 jwin_center_dialog(selcolor_dlg);
6346 int32_t val = do_zqdialog(selcolor_dlg, 3);
6347 ret = D_REDRAW;
6348
6349 zc_set_palette(oldpal);
6350 if(val == 1 || val == 3)
6351 {
6352 d->d1 = selcolor_dlg[3].d1;
6353 GUI_EVENT(d, geCHANGE_VALUE);
6354 ret |= D_REDRAWME;
6355 }
6356 if(d->flags & D_EXIT)
6357 return D_CLOSE;
6358 break;
6359 }
6360 }
6361 return ret;
6362 }
6363
6364 static DIALOG alert_dialog[] =
6365 {
6366 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
6367 { jwin_win_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6368 { d_ctext2_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6369 { d_ctext2_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6370 { d_ctext2_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6371 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6372 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6373 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6374 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6375 };
6376
6377 #define A_S1 1
6378 #define A_S2 2
6379 #define A_S3 3
6380 #define A_B1 4
6381 #define A_B2 5
6382 #define A_B3 6
6383
6384 /* jwin_alert3:
6385 * Displays a simple alert box, containing three lines of text (s1-s3),
6386 * and with either one, two, or three buttons. The text for these buttons
6387 * is passed in b1, b2, and b3 (NULL for buttons which are not used), and
6388 * the keyboard shortcuts in c1 and c2. Returns 1, 2, or 3 depending on
6389 * which button was selected.
6390 */
6391 int32_t jwin_alert3(const char *title, const char *s1, const char *s2, const char *s3, const char *b1, const char *b2, const char *b3, int32_t c1, int32_t c2, int32_t c3, FONT *title_font)
6392 {
6393 int32_t maxlen = 0;
6394 int32_t len1, len2, len3;
6395 int32_t avg_w = text_length(font, " ");
6396 int32_t avg_h = text_height(font)+1;
6397 int32_t buttons = 0;
6398 int32_t yofs = (title ? 22 : 0);
6399 int32_t b[3];
6400 int32_t c;
6401
6402 #define SORT_OUT_BUTTON(x) { \
6403 if (b##x) \
6404 { \
6405 alert_dialog[A_B##x].flags &= ~D_HIDDEN; \
6406 alert_dialog[A_B##x].key = c##x; \
6407 alert_dialog[A_B##x].dp = (void *)b##x; \
6408 len##x = gui_strlen(b##x); \
6409 b[buttons++] = A_B##x; \
6410 } \
6411 else \
6412 { \
6413 alert_dialog[A_B##x].flags |= D_HIDDEN; \
6414 len##x = 0; \
6415 } \
6416 }
6417
6418 if(title_font)
6419 {
6420 alert_dialog[0].dp2=title_font;
6421 }
6422
6423 alert_dialog[A_S1].dp = alert_dialog[A_S2].dp = alert_dialog[A_S3].dp =
6424 alert_dialog[A_B1].dp = alert_dialog[A_B2].dp = (void*)"";
6425
6426 if(s1)
6427 {
6428 alert_dialog[A_S1].dp = (void *)s1;
6429 maxlen = text_length(font, s1);
6430 }
6431
6432 if(s2)
6433 {
6434 alert_dialog[A_S2].dp = (void *)s2;
6435 len1 = text_length(font, s2);
6436
6437 if(len1 > maxlen)
6438 maxlen = len1;
6439 }
6440
6441 if(s3)
6442 {
6443 alert_dialog[A_S3].dp = (void *)s3;
6444 len1 = text_length(font, s3);
6445
6446 if(len1 > maxlen)
6447 maxlen = len1;
6448 }
6449
6450 SORT_OUT_BUTTON(1);
6451 SORT_OUT_BUTTON(2);
6452 SORT_OUT_BUTTON(3);
6453
6454 len1 = MAX(len1, MAX(len2, len3)) + avg_w*3;
6455
6456 if(len1*buttons > maxlen)
6457 maxlen = len1*buttons;
6458
6459 maxlen += avg_w*4;
6460 maxlen=zc_max(text_length(title_font?title_font:font,title)+29,maxlen);
6461 alert_dialog[0].w = maxlen;
6462 alert_dialog[A_S1].x = alert_dialog[A_S2].x = alert_dialog[A_S3].x =
6463 alert_dialog[0].x + maxlen/2;
6464
6465 alert_dialog[A_B1].w = alert_dialog[A_B2].w = alert_dialog[A_B3].w = len1;
6466
6467 alert_dialog[A_B1].x = alert_dialog[A_B2].x = alert_dialog[A_B3].x =
6468 alert_dialog[0].x + maxlen/2 - len1/2;
6469
6470 if(buttons == 3)
6471 {
6472 alert_dialog[b[0]].x = alert_dialog[0].x + maxlen/2 - len1*3/2 - avg_w;
6473 alert_dialog[b[2]].x = alert_dialog[0].x + maxlen/2 + len1/2 + avg_w;
6474 }
6475 else if(buttons == 2)
6476 {
6477 alert_dialog[b[0]].x = alert_dialog[0].x + maxlen/2 - len1 - avg_w;
6478 alert_dialog[b[1]].x = alert_dialog[0].x + maxlen/2 + avg_w;
6479 }
6480
6481 alert_dialog[0].h = avg_h*7 + 13 + yofs;
6482 alert_dialog[A_S1].y = alert_dialog[0].y + avg_h + yofs;
6483 alert_dialog[A_S2].y = alert_dialog[0].y + avg_h*2 + yofs;
6484 alert_dialog[A_S3].y = alert_dialog[0].y + avg_h*3 + yofs;
6485 alert_dialog[A_S1].h = alert_dialog[A_S2].h = alert_dialog[A_S3].h = avg_h;
6486
6487 alert_dialog[A_B1].y = alert_dialog[A_B2].y = alert_dialog[A_B3].y =
6488 alert_dialog[0].y + avg_h*5 + yofs;
6489
6490 alert_dialog[A_B1].h = alert_dialog[A_B2].h = alert_dialog[A_B3].h = avg_h+13;
6491
6492 alert_dialog[0].dp = (void *)title;
6493 alert_dialog[0].flags = (title) ? D_EXIT : 0;
6494
6495 jwin_center_dialog(alert_dialog);
6496 set_dialog_color(alert_dialog, scheme[jcTEXTFG], scheme[jcBOX]);
6497
6498 clear_keybuf();
6499
6500 do
6501 {
6502 rest(1);
6503 }
6504 while(gui_mouse_b());
6505
6506 large_dialog(alert_dialog);
6507 alert_dialog[0].d1 = 0;
6508
6509 c = do_zqdialog(alert_dialog, A_B1);
6510
6511 if(c == A_B1)
6512 return 1;
6513 else if(c == A_B2)
6514 return 2;
6515 else
6516 return 3;
6517 }
6518
6519 /* jwin_alert:
6520 * Displays a simple alert box, containing three lines of text (s1-s3),
6521 * and with either one or two buttons. The text for these buttons is passed
6522 * in b1 and b2 (b2 may be null), and the keyboard shortcuts in c1 and c2.
6523 * Returns 1 or 2 depending on which button was selected.
6524 */
6525 int32_t jwin_alert(const char *title, const char *s1, const char *s2, const char *s3, const char *b1, const char *b2, int32_t c1, int32_t c2, FONT *title_font)
6526 {
6527 int32_t ret;
6528
6529 ret = jwin_alert3(title, s1, s2, s3, b1, b2, NULL, c1, c2, 0, title_font);
6530
6531 if(ret > 2)
6532 ret = 2;
6533
6534 return ret;
6535 }
6536
6537 int32_t d_autotext_proc(int32_t msg, DIALOG *d, int32_t c)
6538 {
6539 ASSERT(d);
6540 ASSERT(d->dp);
6541 #define AUTOBUF_SIZE 8092
6542 static char auto_buf[AUTOBUF_SIZE] = {0};
6543 static int32_t auto_inds[50] = {0};
6544
6545
6546 FONT *oldfont = font;
6547
6548 if (d->dp2)
6549 font = (FONT*)d->dp2;
6550 switch(msg)
6551 {
6552 case MSG_START:
6553 {
6554 memset(auto_buf, 0, AUTOBUF_SIZE);
6555 memset(auto_inds, 0, 50);
6556 char* str = (char*)d->dp;
6557 int32_t len = strlen(str);
6558 int32_t pos = 0, curstrpos = 0, linecount = 1, lastWS = -1;
6559 BITMAP* dummy = create_bitmap_ex(8,8,8);
6560 for(int32_t q = 0; q < len; ++q)
6561 {
6562 switch(str[q])
6563 {
6564 case ' ': case '\t':
6565 lastWS = pos;
6566 break;
6567 case '\n': //Forced newline
6568 auto_inds[linecount++] = ++pos;
6569 curstrpos = pos;
6570 lastWS = -1;
6571 continue; //skip rest of for loop, go to next char
6572 }
6573 auto_buf[pos++] = str[q];
6574 if(gui_textout_ex(dummy,auto_buf+curstrpos,0,0,0,0,0) >= d->w) //too int32_t, wrap to lower line
6575 {
6576 if(lastWS<0)
6577 {
6578 auto_buf[pos-1] = 0;
6579 auto_inds[linecount++] = pos;
6580 curstrpos = pos;
6581 auto_buf[pos++] = str[q];
6582 }
6583 else
6584 {
6585 auto_buf[lastWS] = 0;
6586 auto_inds[linecount++] = lastWS+1;
6587 curstrpos = lastWS+1;
6588 if(gui_textout_ex(dummy,auto_buf+curstrpos,0,0,0,0,0) >= d->w) //STILL too int32_t?
6589 {
6590 auto_buf[pos-1] = 0;
6591 auto_inds[linecount++] = pos;
6592 curstrpos = pos;
6593 auto_buf[pos++] = str[q];
6594 }
6595 lastWS = -1;
6596 }
6597 }
6598 }
6599 destroy_bitmap(dummy);
6600 d->d2 = linecount;
6601 d->h = ((text_height(font) + d->d1) * linecount) - d->d1;
6602 }
6603 break;
6604
6605 case MSG_DRAW:
6606 {
6607 int32_t fg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
6608 int32_t linecount = d->d2;
6609
6610 int32_t yinc = text_height(font)+d->d1;
6611 int32_t y = d->y;
6612 for(int32_t q = 0; q < linecount; ++q)
6613 {
6614 gui_textout_ex(screen, auto_buf+auto_inds[q], d->x, y, fg, d->bg, true);
6615 y += yinc;
6616 }
6617 }
6618 break;
6619 }
6620 font = oldfont;
6621 return D_O_K;
6622 }
6623
6624 static DIALOG alert2_dialog[] =
6625 {
6626 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
6627 { jwin_win_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6628 { d_autotext_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6629 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6630 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6631 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6632 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6633 };
6634
6635 #define A2_S1 1
6636 #define A2_B1 2
6637 #define A2_B2 3
6638 #define A2_B3 4
6639
6640 /* jwin_auto_alert3:
6641 * Displays a simple alert box, containing one line of text, auto-split
6642 * across lines using 'lenlim' and 'vspace,
6643 * and with either one, two, or three buttons. The text for these buttons
6644 * is passed in b1, b2, and b3 (NULL for buttons which are not used), and
6645 * the keyboard shortcuts in c1 and c2. Returns 1, 2, or 3 depending on
6646 * which button was selected.
6647 */
6648 int32_t jwin_auto_alert3(const char *title, const char *s1, int32_t lenlim, int32_t vspace, const char *b1, const char *b2, const char *b3, int32_t c1, int32_t c2, int32_t c3, FONT *title_font)
6649 {
6650 int32_t maxlen = 0;
6651 int32_t len1, len2, len3;
6652 int32_t avg_w = text_length(font, " ");
6653 int32_t avg_h = text_height(font)+1;
6654 int32_t buttons = 0;
6655 int32_t yofs = (title ? 22 : 0);
6656 int32_t b[3];
6657 int32_t c;
6658
6659 #define SORT_OUT_AUTOBUTTON(x) { \
6660 if (b##x) \
6661 { \
6662 alert2_dialog[A2_B##x].flags &= ~D_HIDDEN; \
6663 alert2_dialog[A2_B##x].key = c##x; \
6664 alert2_dialog[A2_B##x].dp = (void *)b##x; \
6665 len##x = gui_strlen(b##x); \
6666 b[buttons++] = A2_B##x; \
6667 } \
6668 else \
6669 { \
6670 alert2_dialog[A2_B##x].flags |= D_HIDDEN; \
6671 len##x = 0; \
6672 } \
6673 }
6674
6675 if(title_font)
6676 {
6677 alert2_dialog[0].dp2=title_font;
6678 }
6679
6680 alert2_dialog[A2_S1].dp = alert2_dialog[A2_B1].dp = alert2_dialog[A2_B2].dp = (void*)"";
6681
6682 if(s1)
6683 {
6684 alert2_dialog[A2_S1].dp = (void *)s1;
6685 maxlen = lenlim;
6686 }
6687
6688 SORT_OUT_AUTOBUTTON(1);
6689 SORT_OUT_AUTOBUTTON(2);
6690 SORT_OUT_AUTOBUTTON(3);
6691
6692 len1 = MAX(len1, MAX(len2, len3)) + avg_w*3;
6693
6694 if(len1*buttons > maxlen)
6695 maxlen = len1*buttons;
6696
6697 maxlen += avg_w*4;
6698 maxlen=zc_max(text_length(title_font?title_font:font,title)+29,maxlen);
6699
6700 alert2_dialog[A2_S1].x = alert2_dialog[0].x + maxlen/2;
6701 alert2_dialog[A2_S1].y = alert2_dialog[0].y + avg_h + yofs;
6702 alert2_dialog[A2_S1].w = lenlim;
6703 alert2_dialog[A2_S1].d1 = vspace;
6704
6705 large_dialog(alert2_dialog);
6706 alert2_dialog[0].d1 = 0;
6707
6708 object_message(&alert2_dialog[A2_S1], MSG_START, 0); //calculate height
6709
6710 alert2_dialog[A2_S1].x = alert2_dialog[0].x + maxlen/2;
6711 alert2_dialog[A2_S1].y = alert2_dialog[0].y + avg_h + yofs;
6712 alert2_dialog[A2_S1].w = lenlim;
6713 alert2_dialog[A2_S1].d1 = vspace;
6714
6715 alert2_dialog[A2_B1].w = alert2_dialog[A2_B2].w = alert2_dialog[A2_B3].w = len1;
6716
6717 alert2_dialog[A2_B1].x = alert2_dialog[A2_B2].x = alert2_dialog[A2_B3].x =
6718 alert2_dialog[0].x + maxlen/2 - len1/2;
6719
6720 if(buttons == 3)
6721 {
6722 alert2_dialog[b[0]].x = alert2_dialog[0].x + maxlen/2 - len1*3/2 - avg_w;
6723 alert2_dialog[b[2]].x = alert2_dialog[0].x + maxlen/2 + len1/2 + avg_w;
6724 }
6725 else if(buttons == 2)
6726 {
6727 alert2_dialog[b[0]].x = alert2_dialog[0].x + maxlen/2 - len1 - avg_w;
6728 alert2_dialog[b[1]].x = alert2_dialog[0].x + maxlen/2 + avg_w;
6729 }
6730
6731 alert2_dialog[0].w = maxlen;
6732 alert2_dialog[0].h = avg_h*4 + yofs + alert2_dialog[A2_S1].h + 13;
6733 alert2_dialog[A2_B1].y = alert2_dialog[A2_B2].y = alert2_dialog[A2_B3].y =
6734 alert2_dialog[0].y + avg_h*2 + yofs + alert2_dialog[A2_S1].h;
6735
6736 alert2_dialog[A2_B1].h = alert2_dialog[A2_B2].h = alert2_dialog[A2_B3].h = avg_h+13;
6737
6738 alert2_dialog[0].dp = (void *)title;
6739 alert2_dialog[0].flags = (title) ? D_EXIT : 0;
6740
6741 jwin_center_dialog(alert2_dialog);
6742 set_dialog_color(alert2_dialog, scheme[jcTEXTFG], scheme[jcBOX]);
6743
6744 clear_keybuf();
6745
6746 do
6747 {
6748 rest(1);
6749 }
6750 while(gui_mouse_b());
6751
6752 large_dialog(alert2_dialog);
6753 alert2_dialog[0].d1 = 0;
6754
6755 c = do_zqdialog(alert2_dialog, A2_B1);
6756
6757 if(c == A2_B1)
6758 return 1;
6759 else if(c == A2_B2)
6760 return 2;
6761 else
6762 return 3;
6763 }
6764
6765 int32_t jwin_auto_alert(const char *title, const char *s1, int32_t lenlim, int32_t vspace, const char *b1, const char *b2, int32_t c1, int32_t c2, FONT *title_font)
6766 {
6767 int32_t ret;
6768
6769 ret = jwin_auto_alert3(title, s1, lenlim, vspace, b1, b2, NULL, c1, c2, 0, title_font);
6770
6771 if(ret > 2)
6772 ret = 2;
6773
6774 return ret;
6775 }
6776
6777 int32_t last_droplist_sel = -1;
6778 static int32_t d_dropcancel_proc(int32_t msg,DIALOG *d,int32_t c)
6779 {
6780 //these are here to bypass compiler warnings about unused arguments
6781 d=d;
6782 c=c;
6783
6784 if(msg==MSG_CLICK || msg==MSG_DCLICK)
6785 return D_CLOSE;
6786
6787 return D_O_K;
6788 }
6789
6790 static DIALOG droplist_dlg[] =
6791 {
6792 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3)*/
6793 { d_dropcancel_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6794 { d_list_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6795 { d_keyboard_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_ESC, (void*)close_dlg, NULL, NULL },
6796 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6797 };
6798
6799 static int32_t droplist(DIALOG *d)
6800 {
6801 ListData *data = (ListData *)d->dp;
6802 int32_t d1 = d->d1;
6803 int32_t listsize, x, y, w, h, max_w;
6804 auto oz = gui_mouse_z();
6805
6806 data->listFunc(-1, &listsize);
6807 y = d->y + d->h;
6808 h = zc_min(abc_patternmatch ? listsize+1 : listsize,8) * text_height(*data->font) + 8;
6809
6810 if(y+h >= zq_screen_h)
6811 {
6812 y = d->y - h;
6813 }
6814
6815 x = d->x;
6816 w = d->w;
6817 max_w = zc_max(d->x+d->w, zq_screen_w-d->x);
6818
6819 for(int32_t i=0; i<listsize; ++i)
6820 {
6821 w=zc_min(max_w,zc_max(w,text_length(*data->font,data->listFunc(i, NULL))+39));
6822 }
6823
6824 if(x+w >= zq_screen_w)
6825 {
6826 x=zq_screen_w-w;
6827 }
6828
6829 droplist_dlg[1] = *d;
6830 droplist_dlg[1].proc = &jwin_abclist_proc;
6831 droplist_dlg[1].flags = D_EXIT + D_USER;
6832 droplist_dlg[1].x = x;
6833 droplist_dlg[1].y = y;
6834 droplist_dlg[1].w = w;
6835 droplist_dlg[1].h = h;
6836 droplist_dlg[1].d2 = listsize<=8 ? 0 : zc_max(d1-3,0);
6837
6838 // cancel
6839 droplist_dlg[0].x = 0;
6840 droplist_dlg[0].y = 0;
6841 droplist_dlg[0].w = zq_screen_w;
6842 droplist_dlg[0].h = zq_screen_h;
6843
6844 if(do_zq_subdialog(droplist_dlg,1)==1)
6845 {
6846 position_mouse_z(oz);
6847 return droplist_dlg[1].d1;
6848 }
6849
6850 position_mouse_z(oz);
6851 return d1;
6852 }
6853
6854 /* jwin_droplist_proc:
6855 * A drop list...
6856 */
6857 int32_t jwin_droplist_proc(int32_t msg,DIALOG *d,int32_t c)
6858 {
6859 int32_t ret;
6860 int32_t down=0, last_draw=0;
6861 int32_t d1;
6862
6863 switch(msg)
6864 {
6865 case MSG_CLICK:
6866 if(mouse_in_rect(d->x+d->w-18,d->y+2,16,d->h))
6867 goto dropit;
6868
6869 break;
6870
6871 case MSG_KEY:
6872 goto dropit;
6873 break;
6874 }
6875
6876 d1 = d->d1;
6877 ret = jwin_list_proc(msg,d,c);
6878
6879 if(d->d1!=d->d2)
6880 {
6881 d->d1=d->d2;
6882 jwin_droplist_proc(MSG_DRAW, d, 0);
6883 }
6884
6885 if(d1 != d->d1)
6886 {
6887 GUI_EVENT(d, geCHANGE_SELECTION);
6888 if(d->flags&D_EXIT)
6889 ret |= D_CLOSE;
6890 }
6891
6892 if(msg == MSG_DRAW)
6893 {
6894 draw_arrow_button(screen, d->x+d->w-18, d->y+2,16, d->h-4, 0, 0);
6895 }
6896
6897 return ret;
6898
6899 dropit:
6900 last_draw = 0;
6901
6902 while(gui_mouse_b())
6903 {
6904 down = mouse_in_rect(d->x+d->w-18,d->y+2,16,d->h);
6905
6906 if(down!=last_draw)
6907 {
6908 draw_arrow_button(screen, d->x+d->w-18, d->y+2,16, d->h-4, 0, down*3);
6909 last_draw = down;
6910 update_hw_screen();
6911 }
6912
6913 clear_keybuf();
6914 rest(1);
6915 }
6916
6917 if(!down)
6918 {
6919 return D_O_K;
6920 }
6921
6922 draw_arrow_button(screen, d->x+d->w-18, d->y+2,16, d->h-4, 0, 0);
6923
6924 d1 = d->d1;
6925 d->d2 = d->d1 = droplist(d);
6926
6927 object_message(d, MSG_DRAW, 0);
6928
6929 while(gui_mouse_b())
6930 {
6931 clear_keybuf();
6932 rest(1);
6933 update_hw_screen();
6934 }
6935
6936 if(d1!=d->d1)
6937 GUI_EVENT(d, geCHANGE_SELECTION);
6938
6939 return ((d1 != d->d1) && (d->flags&D_EXIT)) ? D_CLOSE : D_O_K;
6940 }
6941
6942
6943 int32_t jwin_abclist_proc(int32_t msg,DIALOG *d,int32_t c)
6944 {
6945 ListData *data = (ListData *)d->dp;
6946 if(msg == MSG_START) wipe_abc_keypresses();
6947
6948 if(msg == MSG_CHAR && (key_shifts&KB_CTRL_FLAG))
6949 return D_O_K;
6950
6951 if(abc_patternmatch) // Search style pattern match.
6952 {
6953 if(msg==MSG_CHAR && ((c&0xFF) > 31) && ((c&0xFF) < 127)) //(isalpha(c&0xFF) || isdigit(c&0xFF)))
6954 {
6955 int32_t max,dummy,h;
6956
6957 h = ((d->h-3) / text_height(*data->font))-1;
6958 if ( isalpha(c&0xFF) ) c = toupper(c&0xFF);
6959 for ( int32_t q = 0; q < 1023; ++q )
6960 {
6961 if ( !(abc_keypresses[q]) )
6962 {
6963 abc_keypresses[q] = (char)c;
6964 break;
6965 }
6966 }
6967 data->listFunc(-1, &max);
6968
6969 int32_t cur = d->d1;
6970 int32_t charpos = 0; int32_t listpos = 0; int32_t lastmatch = -1;
6971 char tmp[1024] = { 0 };
6972 char lsttmp[1024] = { 0 };
6973 int32_t lastmatches[32768] = {0};
6974 for ( int32_t a = 0; a < 32768; ++a ) lastmatches[a] = -1;
6975 int32_t lmindx = 0;
6976
6977 bool foundmatch = false;
6978 bool numsearch = true;
6979 for ( int32_t q = 0; q < 1023; ++q )
6980 {
6981 if(!abc_keypresses[q]) break;
6982 if(!isdigit(abc_keypresses[q]))
6983 {
6984 if(q == 0 && abc_keypresses[q] == '-')
6985 continue;
6986 numsearch = false;
6987 break;
6988 }
6989 }
6990 if(numsearch) //Indexed search, first
6991 {
6992 int32_t num = atoi(abc_keypresses);
6993 //Find a different indexing type in the strings?
6994 if(!foundmatch)
6995 {
6996 char buf[16];
6997 if(num < 0) sprintf(buf, "(%04d)", num);
6998 else sprintf(buf, "(%03d)", num);
6999 std::string cmp = buf;
7000 for(int32_t listpos = 0; listpos < max; ++listpos)
7001 {
7002 std::string str((data->listFunc(listpos,&dummy)));
7003 size_t trimpos = str.find_last_not_of("-(0123456789)");
7004 if(trimpos != std::string::npos) ++trimpos;
7005 str.erase(0, trimpos);
7006 if(cmp == str)
7007 {
7008 d->d1 = listpos;
7009 d->d2 = zc_max(zc_min(listpos-(h>>1), max-h), 0);
7010 foundmatch = true;
7011 break;
7012 }
7013 }
7014 }
7015 //Search for match with first number in string?
7016 if(!foundmatch)
7017 {
7018 auto buf = fmt::format("{}", num);
7019 for(int32_t listpos = 0; listpos < max; ++listpos)
7020 {
7021 std::string str((data->listFunc(listpos,&dummy)));
7022 size_t pos1 = -1;
7023 do
7024 {
7025 pos1 = str.find_first_of("-0123456789", pos1+1);
7026 } while(pos1 != string::npos && str[pos1] == '-' && pos1+1 < str.size() && !isdigit(str[pos1+1]));
7027 if(pos1 == string::npos)
7028 continue;
7029 size_t pos2 = str.find_first_not_of("-0123456789", pos1);
7030 if(pos2 == string::npos)
7031 continue;
7032 str = str.substr(pos1,pos2-pos1);
7033 if(buf == str)
7034 {
7035 d->d1 = listpos;
7036 d->d2 = zc_max(zc_min(listpos-(h>>1), max-h), 0);
7037 foundmatch = true;
7038 break;
7039 }
7040 }
7041 }
7042 }
7043 if(!foundmatch)
7044 {
7045 strcpy(tmp, abc_keypresses);
7046 for ( int32_t listpos = 0; listpos < max; ++listpos )
7047 {
7048 memset(lsttmp, 0, 1024);
7049 strcpy(lsttmp, ((data->listFunc(listpos,&dummy))));
7050
7051 if ( !(strnicmp(lsttmp, tmp, strlen(tmp))))
7052 {
7053 d->d1 = listpos;
7054 d->d2 = zc_max(zc_min(listpos-(h>>1), max-h), 0);
7055 foundmatch = true;
7056 break;
7057 }
7058 }
7059 }
7060 if(foundmatch)
7061 GUI_EVENT(d, geCHANGE_SELECTION);
7062 d->flags |= D_DIRTY;
7063 if ( gui_mouse_b() ) wipe_abc_keypresses();
7064 return foundmatch ? D_USED_CHAR : D_O_K;
7065 }
7066 else if(msg==MSG_CHAR && ( (c&0xFF) == 8) )//backspace
7067 {
7068 for ( int32_t q = 1023; q >= 0; --q )
7069 {
7070 if ( abc_keypresses[q] )
7071 {
7072 d->flags |= D_DIRTY;
7073 abc_keypresses[q] = '\0'; break;
7074 }
7075 }
7076 return D_USED_CHAR;
7077 }
7078 if ( gui_mouse_b() ) { wipe_abc_keypresses(); }
7079 }
7080 else // Windows Explorer style jumping
7081 {
7082 if(msg==MSG_CHAR && (isalpha(c&0xFF) || isdigit(c&0xFF)))
7083 {
7084 int32_t max,dummy,h,i;
7085
7086 h = (d->h-3) / text_height(*data->font);
7087 c = toupper(c&0xFF);
7088
7089 data->listFunc(-1, &max);
7090
7091 int32_t cur = d->d1;
7092 bool foundmatch = false;
7093 for(i=cur+1; (cur ? (i != cur) : (cur < max)); ++i) //don't infinite loop this.
7094 {
7095 if(i>=max) i=0;
7096 if(toupper((data->listFunc(i,&dummy))[0]) == c)
7097 {
7098 d->d1 = i;
7099 d->d2 = zc_max(zc_min(i-(h>>1), max-h), 0);
7100 foundmatch = true;
7101 break;
7102 }
7103 }
7104
7105 d->flags |= D_DIRTY;
7106 return foundmatch ? D_USED_CHAR : D_O_K;
7107 }
7108 }
7109 if ( gui_mouse_b() ) { wipe_abc_keypresses(); }
7110 return ((abc_patternmatch) ? jwin_do_abclist_proc(msg,d,c) : jwin_list_proc(msg,d,c));
7111 }
7112
7113 int32_t jwin_checkfont_proc(int32_t msg, DIALOG *d, int32_t c)
7114 {
7115
7116 FONT *oldfont = font;
7117
7118 if(d->dp2)
7119 {
7120 font = (FONT *)d->dp2;
7121 }
7122
7123 int32_t rval = jwin_check_proc(msg, d, c);
7124 font = oldfont;
7125 return rval;
7126 }
7127
7128 /* jwin_check_proc:
7129 * Who needs C++ after all? This is derived from d_button_proc,
7130 * but overrides the drawing routine to provide a check box.
7131 */
7132 int32_t jwin_check_proc(int32_t msg, DIALOG *d, int32_t c)
7133 {
7134 //these are here to bypass compiler warnings about unused arguments
7135 c=c;
7136 int32_t x;
7137 int32_t bx=0, tl=0;
7138 int32_t tx=d->x;
7139 ASSERT(d);
7140
7141 switch(msg)
7142 {
7143 case MSG_DRAW:
7144 x = d->x;
7145
7146 if(!(d->d1))
7147 {
7148 if(d->dp)
7149 {
7150 if(d->flags & D_DISABLED)
7151 {
7152 gui_textout_ln(screen, (uint8_t *)d->dp, tx+1, d->y+1+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcLIGHT], scheme[jcBOX], 0);
7153 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcDISABLED_FG], -1, 0);
7154 bx=tl+text_height(font)/2;
7155 }
7156 else
7157 {
7158 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcBOXFG], scheme[jcBOX], 0);
7159 bx=tl+text_height(font)/2;
7160 }
7161 }
7162 }
7163
7164 jwin_draw_frame(screen, x+bx, d->y, d->h, d->h, FR_DEEP);
7165
7166 if(!(d->flags & D_DISABLED))
7167 {
7168 rectfill(screen, x+bx+2, d->y+2, x+bx+d->h-3, d->y+d->h-3, scheme[jcTEXTBG]);
7169 }
7170
7171 if(d->d1)
7172 {
7173 tx=x+bx+d->h-1+(text_height(font)/2);
7174
7175 if(d->dp)
7176 {
7177 if(d->flags & D_DISABLED)
7178 {
7179 gui_textout_ln(screen, (uint8_t *)d->dp, tx+1, d->y+1+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcLIGHT], scheme[jcBOX], 0);
7180 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcDISABLED_FG], -1, 0);
7181 }
7182 else
7183 {
7184 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcBOXFG], scheme[jcBOX], 0);
7185 }
7186 }
7187 }
7188
7189 if(d->flags & D_SELECTED)
7190 {
7191 line(screen, x+bx+2, d->y+2, x+bx+d->h-3, d->y+d->h-3, scheme[jcTEXTFG]);
7192 line(screen, x+bx+2, d->y+d->h-3, x+bx+d->h-3, d->y+2, scheme[jcTEXTFG]);
7193 }
7194
7195 d->w=int32_t(text_height(font)*1.5);
7196
7197 if(d->dp)
7198 {
7199 // dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+d->h-1, (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7200 dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+(text_height(font)), (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7201 d->w+=tl+1;
7202 }
7203
7204 return D_O_K;
7205 break;
7206 }
7207
7208 return d_jwinbutton_proc(msg, d, 0);
7209 }
7210
7211 int32_t new_check_proc(int32_t msg, DIALOG *d, int32_t)
7212 {
7213 int32_t bx=0, tl=0;
7214 ASSERT(d);
7215
7216 FONT *oldfont = font;
7217 uint8_t* str = (uint8_t*)d->dp;
7218 bool has_text = str && str[0];
7219 if(d->dp2)
7220 {
7221 font = (FONT *)d->dp2;
7222 }
7223 switch(msg)
7224 {
7225 case MSG_DRAW:
7226 {
7227 const int box_spacing = 4;
7228 int32_t tx = 2, ty = 2, tx2 = 2;
7229 int fh = text_height(font);
7230 auto txt_y = ty+(d->h-fh)/2;
7231 BITMAP* tmp = create_bitmap_ex(8, d->w+4, d->h+4);
7232 clear_bitmap(tmp);
7233 set_clip_rect(tmp, tx, ty, tmp->w-tx, tmp->h-ty);
7234 if(!(d->d1))
7235 {
7236 if(has_text)
7237 {
7238 if(d->flags & D_DISABLED)
7239 {
7240 gui_textout_ln(tmp, str, tx+1, txt_y+1, scheme[jcLIGHT], scheme[jcBOX], 0);
7241 tl=gui_textout_ln(tmp, str, tx, txt_y, scheme[jcDISABLED_FG], -1, 0);
7242 bx=tl+box_spacing;
7243 }
7244 else
7245 {
7246 tl=gui_textout_ln(tmp, str, tx, txt_y, scheme[jcBOXFG], scheme[jcBOX], 0);
7247 bx=tl+box_spacing;
7248 }
7249 }
7250 }
7251
7252 jwin_draw_frame(tmp, tx+bx, ty, d->h, d->h, FR_DEEP);
7253
7254 if(!(d->flags & D_DISABLED))
7255 {
7256 rectfill(tmp, tx+bx+2, ty+2, tx+bx+d->h-3, ty+d->h-3, scheme[jcTEXTBG]);
7257 }
7258
7259 if(d->d1)
7260 {
7261 tx2=tx+bx+d->h-1+box_spacing;
7262
7263 if(has_text)
7264 {
7265 if(d->flags & D_DISABLED)
7266 {
7267 gui_textout_ln(tmp, str, tx2+1, txt_y+1, scheme[jcLIGHT], scheme[jcBOX], 0);
7268 tl=gui_textout_ln(tmp, str, tx2, txt_y, scheme[jcDISABLED_FG], -1, 0);
7269 }
7270 else
7271 {
7272 tl=gui_textout_ln(tmp, str, tx2, txt_y, scheme[jcBOXFG], scheme[jcBOX], 0);
7273 }
7274 }
7275 }
7276
7277 if(d->flags & D_SELECTED)
7278 {
7279 line(tmp, tx+bx+2, ty+2, tx+bx+d->h-3, ty+d->h-3, scheme[jcTEXTFG]);
7280 line(tmp, tx+bx+2, ty+d->h-3, tx+bx+d->h-3, ty+2, scheme[jcTEXTFG]);
7281 }
7282
7283 set_clip_rect(tmp, 0, 0, tmp->w, tmp->h);
7284 if(has_text)
7285 {
7286 dotted_rect(tmp, tx2-1, txt_y-1, tx2+tl, txt_y+fh, (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7287 }
7288
7289 masked_blit(tmp, screen, 0, 0, d->x-tx, d->y-ty, d->w+tx+tx, d->h+ty+ty);
7290 break;
7291 }
7292 }
7293
7294 int32_t rval = D_O_K;
7295 if(msg != MSG_DRAW)
7296 rval = d_jwinbutton_proc(msg, d, 0);
7297 font = oldfont;
7298 return rval;
7299 }
7300
7301 int32_t jwin_radiofont_proc(int32_t msg, DIALOG *d, int32_t c)
7302 {
7303 FONT *oldfont = font;
7304
7305 if(d->dp2)
7306 {
7307 font = (FONT *)d->dp2;
7308 }
7309
7310 int32_t rval = jwin_radio_proc(msg, d, c);
7311 font = oldfont;
7312 return rval;
7313 }
7314
7315 /* jwin_radio_proc:
7316 * GUI procedure for radio buttons.
7317 * Parameters: d1-button group number; d2-button style (0=circle,1=square);
7318 * dp-text to appear as label to the right of the button.
7319 */
7320 int32_t jwin_radio_proc(int32_t msg, DIALOG *d, int32_t c)
7321 {
7322 int32_t x, center, r, ret, tl=0, tx;
7323 ASSERT(d);
7324
7325 switch(msg)
7326 {
7327 case MSG_DRAW:
7328 // tx=d->x+d->h-1+text_height(font);
7329 tx=d->x+int32_t(text_height(font)*1.5);
7330
7331 if(d->dp)
7332 {
7333 if(d->flags & D_DISABLED)
7334 {
7335 gui_textout_ln(screen, (uint8_t *)d->dp, tx+1, d->y+1+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcLIGHT], scheme[jcBOX], 0);
7336 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcDISABLED_FG], -1, 0);
7337 }
7338 else
7339 {
7340 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcBOXFG], scheme[jcBOX], 0);
7341 }
7342 }
7343
7344 x = d->x;
7345 r = d->h/2;
7346
7347 center = x+r;
7348 rectfill(screen, x, d->y, x+d->h-1, d->y+d->h-1, scheme[jcBOX]);
7349
7350 switch(d->d2)
7351 {
7352 case 1:
7353 jwin_draw_frame(screen, x, d->y, d->h, d->h, FR_DEEP);
7354
7355 if(!(d->flags & D_DISABLED))
7356 {
7357 rectfill(screen, x+2, d->y+2, x+d->h-3, d->y+d->h-3, scheme[jcLIGHT]);
7358 }
7359
7360 if(d->flags & D_SELECTED)
7361 {
7362 rectfill(screen, x+r/2, d->y+r/2, x+d->h-1-r/2, d->y+d->h-1-r/2, scheme[jcDARK]);
7363 //line(screen, x+2, d->y+2, x+d->h-3, d->y+d->h-3, scheme[jcDARK]);
7364 //line(screen, x+2, d->y+d->h-3, x+d->h-3, d->y+2, scheme[jcDARK]);
7365 }
7366
7367 break;
7368
7369 default:
7370 circlefill(screen, center, d->y+r, r, scheme[jcTEXTBG]);
7371 arc(screen, center, d->y+r, itofix(32), itofix(160), r, vc(0));
7372 circlefill(screen, center, d->y+r, r-1, scheme[jcTEXTBG]);
7373 arc(screen, center, d->y+r, itofix(32), itofix(160), r-1, vc(0));
7374 circlefill(screen, center, d->y+r, r-2, (d->flags & D_DISABLED)?scheme[jcDISABLED_BG]:scheme[jcTEXTBG]);
7375
7376 if(d->flags & D_SELECTED)
7377 {
7378 circlefill(screen, center, d->y+r, r-3, scheme[jcTEXTFG]);
7379 }
7380
7381 break;
7382 }
7383
7384 if(d->dp)
7385 {
7386 // dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+d->h-1, (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7387 dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+(text_height(font)), (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7388 d->w=tl+int32_t(text_height(font)*1.5)+1;
7389 }
7390
7391 return D_O_K;
7392
7393 case MSG_KEY:
7394 case MSG_CLICK:
7395 if(d->flags & D_SELECTED)
7396 {
7397 return D_O_K;
7398 }
7399
7400 break;
7401
7402 case MSG_RADIO:
7403 if((c == d->d1) && (d->flags & D_SELECTED))
7404 {
7405 d->flags &= ~D_SELECTED;
7406 object_message(d, MSG_DRAW, 0);
7407 }
7408
7409 break;
7410 }
7411
7412 ret = d_jwinbutton_proc(msg, d, 0);
7413
7414 if(((msg==MSG_KEY) || (msg==MSG_CLICK)) && (d->flags & D_SELECTED) && (!(d->flags & D_EXIT)))
7415 {
7416 d->flags &= ~D_SELECTED;
7417 broadcast_dialog_message(MSG_RADIO, d->d1);
7418 d->flags |= D_SELECTED;
7419 GUI_EVENT(d, geRADIO);
7420 }
7421
7422 return ret;
7423 }
7424
7425
7426 /* 1.5k lookup table for color matching */
7427 uint32_t col_diff[3*128];
7428
7429 /* bestfit_init:
7430 * Color matching is done with weighted squares, which are much faster
7431 * if we pregenerate a little lookup table...
7432 */
7433 71 void bestfit_init(void)
7434 {
7435 int32_t i;
7436
7437 71 col_diff[0] = col_diff[128] = col_diff[256] = 0;
7438
7439
2/2
✓ Branch 0 taken 4473 times.
✓ Branch 1 taken 71 times.
4544 for(i=1; i<64; i++)
7440 {
7441 4473 int32_t k = i * i;
7442 4473 col_diff[0 +i] = col_diff[0 +128-i] = k * (59 * 59);
7443 4473 col_diff[128+i] = col_diff[128+128-i] = k * (30 * 30);
7444 4473 col_diff[256+i] = col_diff[256+128-i] = k * (11 * 11);
7445 4473 }
7446 71 }
7447
7448
7449
7450 /* bestfit_color:
7451 * Searches a palette for the color closest to the requested R, G, B value.
7452 */
7453 int32_t bestfit_color_range(AL_CONST PALETTE pal, int32_t r, int32_t g, int32_t b, uint8_t start, uint8_t end)
7454 {
7455 int32_t i, coldiff, lowest, bestfit;
7456
7457 if(col_diff[1] == 0)
7458 bestfit_init();
7459
7460 bestfit = start;
7461 lowest = INT_MAX;
7462
7463 i = start;
7464
7465 while(i<PAL_SIZE&&i<=end)
7466 {
7467 AL_CONST RGB *rgb = &pal[i];
7468 coldiff = (col_diff + 0) [(rgb->g - g) & 0x7F ];
7469
7470 if(coldiff < lowest)
7471 {
7472 coldiff += (col_diff + 128) [(rgb->r - r) & 0x7F ];
7473
7474 if(coldiff < lowest)
7475 {
7476 coldiff += (col_diff + 256) [(rgb->b - b) & 0x7F ];
7477
7478 if(coldiff < lowest)
7479 {
7480 bestfit = rgb - pal; /* faster than `bestfit = i;' */
7481
7482 if(coldiff == 0)
7483 {
7484 return bestfit;
7485 }
7486
7487 lowest = coldiff;
7488 }
7489 }
7490 }
7491
7492 i++;
7493 }
7494
7495 return bestfit;
7496 }
7497
7498
7499 /* makecol8:
7500 * Converts R, G, and B values (ranging 0-255) to an 8 bit paletted color.
7501 * If the global rgb_map table is initialised, it uses that, otherwise
7502 * it searches through the current palette to find the best match.
7503 */
7504 int32_t makecol8_map(int32_t r, int32_t g, int32_t b, RGB_MAP *table)
7505 {
7506 return table->data[r>>3][g>>3][b>>3];
7507 }
7508
7509
7510 /* create_rgb_table:
7511 * Fills an RGB_MAP lookup table with conversion data for the specified
7512 * palette. This is the faster version by Jan Hubicka.
7513 *
7514 * Uses alg. similar to floodfill - it adds one seed per every color in
7515 * palette to its best position. Then areas around seed are filled by
7516 * same color because it is best approximation for them, and then areas
7517 * about them etc...
7518 *
7519 * It does just about 80000 tests for distances and this is about 100
7520 * times better than normal 256*32000 tests so the calculation time
7521 * is now less than one second at all computers I tested.
7522 */
7523 8193 void create_rgb_table_range(RGB_MAP *table, AL_CONST PALETTE pal_8bit, uint8_t start, uint8_t end, void (*callback)(int32_t pos))
7524 {
7525 #define UNUSED 65535
7526 #define LAST 65532
7527
7528 // Allegro has been modified to use an 8 bit palette, but this method and RGB_MAP still use 6 bit.
7529 PALETTE pal;
7530
2/2
✓ Branch 0 taken 2097408 times.
✓ Branch 1 taken 8193 times.
2105601 for (int i = 0; i < 256; i++)
7531 {
7532 2097408 pal[i] = pal_8bit[i];
7533 2097408 pal[i].r /= 4;
7534 2097408 pal[i].g /= 4;
7535 2097408 pal[i].b /= 4;
7536 2097408 }
7537
7538 /* macro add adds to single linked list */
7539 #define add(i) (next[(i)] == UNUSED ? (next[(i)] = LAST, \
7540 (first != LAST ? (next[last] = (i)) : (first = (i))), \
7541 (last = (i))) : 0)
7542
7543 /* same but w/o checking for first element */
7544 #define add1(i) (next[(i)] == UNUSED ? (next[(i)] = LAST, \
7545 next[last] = (i), \
7546 (last = (i))) : 0)
7547
7548 /* calculates distance between two colors */
7549 #define dist(a1, a2, a3, b1, b2, b3) \
7550 (col_diff[ ((a2) - (b2)) & 0x7F] + \
7551 (col_diff + 128)[((a1) - (b1)) & 0x7F] + \
7552 (col_diff + 256)[((a3) - (b3)) & 0x7F])
7553
7554 /* converts r,g,b to position in array and back */
7555 #define pos(r, g, b) \
7556 (((r) / 2) * 32 * 32 + ((g) / 2) * 32 + ((b) / 2))
7557
7558 #define depos(pal, r, g, b) \
7559 ((b) = ((pal) & 31) * 2, \
7560 (g) = (((pal) >> 5) & 31) * 2, \
7561 (r) = (((pal) >> 10) & 31) * 2)
7562
7563 /* is current color better than pal1? */
7564 #define better(r1, g1, b1, pal1) \
7565 (((int32_t)dist((r1), (g1), (b1), \
7566 (pal1).r, (pal1).g, (pal1).b)) > (int32_t)dist2)
7567
7568 /* checking of position */
7569 #define dopos(rp, gp, bp, ts) \
7570 if ((rp > -1 || r > 0) && (rp < 1 || r < 61) && \
7571 (gp > -1 || g > 0) && (gp < 1 || g < 61) && \
7572 (bp > -1 || b > 0) && (bp < 1 || b < 61)) { \
7573 i = first + rp * 32 * 32 + gp * 32 + bp; \
7574 if (!data[i]) { \
7575 data[i] = val; \
7576 add1(i); \
7577 } \
7578 else if ((ts) && (data[i] != val)) { \
7579 dist2 = (rp ? (col_diff+128)[(r+2*rp-pal[val].r) & 0x7F] : r2) + \
7580 (gp ? (col_diff )[(g+2*gp-pal[val].g) & 0x7F] : g2) + \
7581 (bp ? (col_diff+256)[(b+2*bp-pal[val].b) & 0x7F] : b2); \
7582 if (better((r+2*rp), (g+2*gp), (b+2*bp), pal[data[i]])) { \
7583 data[i] = val; \
7584 add1(i); \
7585 } \
7586 } \
7587 }
7588
7589 int32_t i, curr, r, g, b, val, dist2;
7590 uint32_t r2, g2, b2;
7591 uint16_t next[32*32*32];
7592 uint8_t *data;
7593 8193 int32_t first = LAST;
7594 8193 int32_t last = LAST;
7595 8193 int32_t count = 0;
7596 8193 int32_t cbcount = 0;
7597
7598 #define AVERAGE_COUNT 18000
7599
7600
2/2
✓ Branch 0 taken 8131 times.
✓ Branch 1 taken 62 times.
8193 if(col_diff[1] == 0)
7601 62 bestfit_init();
7602
7603 8193 memset(next, 255, sizeof(next));
7604 8193 memset(table->data, 0, sizeof(char)*32*32*32);
7605
7606 8193 data = (uint8_t *)table->data;
7607
7608 /* add starting seeds for floodfill */
7609
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 270369 times.
✓ Branch 2 taken 262176 times.
✓ Branch 3 taken 8193 times.
270369 for(i=start; i<PAL_SIZE&&i<=end; i++)
7610 {
7611 262176 curr = pos(pal[i].r, pal[i].g, pal[i].b);
7612
7613
2/2
✓ Branch 0 taken 93952 times.
✓ Branch 1 taken 168224 times.
262176 if(next[curr] == UNUSED)
7614 {
7615 168224 data[curr] = i;
7616
3/4
✓ Branch 0 taken 168224 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 160031 times.
✓ Branch 3 taken 8193 times.
168224 add(curr);
7617 168224 }
7618 262176 }
7619
7620 /* main floodfill: two versions of loop for faster growing in blue axis */
7621
2/2
✓ Branch 0 taken 8193 times.
✓ Branch 1 taken 156244017 times.
156252210 while(first < LAST)
7622 {
7623 156244017 depos(first, r, g, b);
7624
7625 /* calculate distance of current color */
7626 156244017 val = data[first];
7627 156244017 r2 = (col_diff+128)[((pal[val].r)-(r)) & 0x7F];
7628 156244017 g2 = (col_diff)[((pal[val].g)-(g)) & 0x7F];
7629 156244017 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7F];
7630
7631 /* try to grow to all directions */
7632 #ifdef _MSC_VER
7633 #pragma warning(disable:4127)
7634 #endif
7635
11/12
✓ Branch 0 taken 4209919 times.
✓ Branch 1 taken 152034098 times.
✓ Branch 2 taken 138628870 times.
✓ Branch 3 taken 13405228 times.
✓ Branch 4 taken 13405228 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 127484607 times.
✓ Branch 7 taken 11144263 times.
✓ Branch 8 taken 2996170 times.
✓ Branch 9 taken 8148093 times.
✓ Branch 10 taken 19209 times.
✓ Branch 11 taken 8128884 times.
294872887 dopos(0, 0, 1, 1);
7636
11/12
✓ Branch 0 taken 7155904 times.
✓ Branch 1 taken 149088113 times.
✓ Branch 2 taken 149077865 times.
✓ Branch 3 taken 10248 times.
✓ Branch 4 taken 10248 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 147429336 times.
✓ Branch 7 taken 1648529 times.
✓ Branch 8 taken 695948 times.
✓ Branch 9 taken 952581 times.
✓ Branch 10 taken 940288 times.
✓ Branch 11 taken 12293 times.
305321882 dopos(0, 0,-1, 1);
7637
11/12
✓ Branch 0 taken 4277767 times.
✓ Branch 1 taken 151966250 times.
✓ Branch 2 taken 151090454 times.
✓ Branch 3 taken 875796 times.
✓ Branch 4 taken 875796 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 117777601 times.
✓ Branch 7 taken 33312853 times.
✓ Branch 8 taken 33250885 times.
✓ Branch 9 taken 61968 times.
✓ Branch 10 taken 23552 times.
✓ Branch 11 taken 38416 times.
307334471 dopos(1, 0, 0, 1);
7638
11/12
✓ Branch 0 taken 6558218 times.
✓ Branch 1 taken 149685799 times.
✓ Branch 2 taken 149675042 times.
✓ Branch 3 taken 10757 times.
✓ Branch 4 taken 10757 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 112583968 times.
✓ Branch 7 taken 37091074 times.
✓ Branch 8 taken 30262889 times.
✓ Branch 9 taken 6828185 times.
✓ Branch 10 taken 6396208 times.
✓ Branch 11 taken 431977 times.
305919059 dopos(-1, 0, 0, 1);
7639
11/12
✓ Branch 0 taken 5435342 times.
✓ Branch 1 taken 150808675 times.
✓ Branch 2 taken 129595197 times.
✓ Branch 3 taken 21213478 times.
✓ Branch 4 taken 21213478 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 109488150 times.
✓ Branch 7 taken 20107047 times.
✓ Branch 8 taken 3416418 times.
✓ Branch 9 taken 16690629 times.
✓ Branch 10 taken 14569229 times.
✓ Branch 11 taken 2121400 times.
285839214 dopos(0, 1, 0, 1);
7640
11/12
✓ Branch 0 taken 4179962 times.
✓ Branch 1 taken 152064055 times.
✓ Branch 2 taken 151854857 times.
✓ Branch 3 taken 209198 times.
✓ Branch 4 taken 209198 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 139895210 times.
✓ Branch 7 taken 11959647 times.
✓ Branch 8 taken 11841357 times.
✓ Branch 9 taken 118290 times.
✓ Branch 10 taken 88075 times.
✓ Branch 11 taken 30215 times.
308098874 dopos(0,-1, 0, 1);
7641 #ifdef _MSC_VER
7642 #pragma warning(default:4127)
7643 #endif
7644
7645 /* faster growing of blue direction */
7646
4/4
✓ Branch 0 taken 149088113 times.
✓ Branch 1 taken 7155904 times.
✓ Branch 2 taken 695948 times.
✓ Branch 3 taken 148392165 times.
156244017 if((b > 0) && (data[first-1] == val))
7647 {
7648 148392165 b -= 2;
7649 148392165 first--;
7650 148392165 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7F];
7651
7652 #ifdef _MSC_VER
7653 #pragma warning(disable:4127)
7654 #endif
7655
5/6
✓ Branch 0 taken 6158035 times.
✓ Branch 1 taken 142234130 times.
✓ Branch 2 taken 142232849 times.
✓ Branch 3 taken 1281 times.
✓ Branch 4 taken 1281 times.
✗ Branch 5 not taken.
290625014 dopos(-1, 0, 0, 0);
7656
5/6
✓ Branch 0 taken 4148725 times.
✓ Branch 1 taken 144243440 times.
✓ Branch 2 taken 144170688 times.
✓ Branch 3 taken 72752 times.
✓ Branch 4 taken 72752 times.
✗ Branch 5 not taken.
292562853 dopos(1, 0, 0, 0);
7657
5/6
✓ Branch 0 taken 4018152 times.
✓ Branch 1 taken 144374013 times.
✓ Branch 2 taken 144334308 times.
✓ Branch 3 taken 39705 times.
✓ Branch 4 taken 39705 times.
✗ Branch 5 not taken.
292726473 dopos(0,-1, 0, 0);
7658
5/6
✓ Branch 0 taken 5157006 times.
✓ Branch 1 taken 143235159 times.
✓ Branch 2 taken 142760097 times.
✓ Branch 3 taken 475062 times.
✓ Branch 4 taken 475062 times.
✗ Branch 5 not taken.
291152262 dopos(0, 1, 0, 0);
7659 #ifdef _MSC_VER
7660 #pragma warning(default:4127)
7661 #endif
7662
7663 148392165 first++;
7664 148392165 }
7665
7666 /* get next from list */
7667 156244017 i = first;
7668 156244017 first = next[first];
7669 156244017 next[i] = UNUSED;
7670
7671 /* second version of loop */
7672
2/2
✓ Branch 0 taken 6401 times.
✓ Branch 1 taken 156237616 times.
156244017 if(first != LAST)
7673 {
7674 156237616 depos(first, r, g, b);
7675
7676 156237616 val = data[first];
7677 156237616 r2 = (col_diff+128)[((pal[val].r)-(r)) & 0x7F];
7678 156237616 g2 = (col_diff)[((pal[val].g)-(g)) & 0x7F];
7679 156237616 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7F];
7680
7681 #ifdef _MSC_VER
7682 #pragma warning(disable:4127)
7683 #endif
7684
11/12
✓ Branch 0 taken 4201476 times.
✓ Branch 1 taken 152036140 times.
✓ Branch 2 taken 135815700 times.
✓ Branch 3 taken 16220440 times.
✓ Branch 4 taken 16220440 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 126421700 times.
✓ Branch 7 taken 9394000 times.
✓ Branch 8 taken 3029458 times.
✓ Branch 9 taken 6364542 times.
✓ Branch 10 taken 17157 times.
✓ Branch 11 taken 6347385 times.
292053316 dopos(0, 0, 1, 1);
7685
11/12
✓ Branch 0 taken 7226297 times.
✓ Branch 1 taken 149011319 times.
✓ Branch 2 taken 149009527 times.
✓ Branch 3 taken 1792 times.
✓ Branch 4 taken 1792 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 147401987 times.
✓ Branch 7 taken 1607540 times.
✓ Branch 8 taken 666245 times.
✓ Branch 9 taken 941295 times.
✓ Branch 10 taken 925413 times.
✓ Branch 11 taken 15882 times.
305247143 dopos(0, 0,-1, 1);
7686
11/12
✓ Branch 0 taken 4111865 times.
✓ Branch 1 taken 152125751 times.
✓ Branch 2 taken 150974247 times.
✓ Branch 3 taken 1151504 times.
✓ Branch 4 taken 1151504 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 117321849 times.
✓ Branch 7 taken 33652398 times.
✓ Branch 8 taken 33599908 times.
✓ Branch 9 taken 52490 times.
✓ Branch 10 taken 21504 times.
✓ Branch 11 taken 30986 times.
307211863 dopos(1, 0, 0, 1);
7687
11/12
✓ Branch 0 taken 6288945 times.
✓ Branch 1 taken 149948671 times.
✓ Branch 2 taken 149941245 times.
✓ Branch 3 taken 7426 times.
✓ Branch 4 taken 7426 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 112698473 times.
✓ Branch 7 taken 37242772 times.
✓ Branch 8 taken 30413108 times.
✓ Branch 9 taken 6829664 times.
✓ Branch 10 taken 6465286 times.
✓ Branch 11 taken 364378 times.
306178861 dopos(-1, 0, 0, 1);
7688
11/12
✓ Branch 0 taken 5556413 times.
✓ Branch 1 taken 150681203 times.
✓ Branch 2 taken 104743863 times.
✓ Branch 3 taken 45937340 times.
✓ Branch 4 taken 45937340 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 85359584 times.
✓ Branch 7 taken 19384279 times.
✓ Branch 8 taken 3471214 times.
✓ Branch 9 taken 15913065 times.
✓ Branch 10 taken 14438667 times.
✓ Branch 11 taken 1474398 times.
260981479 dopos(0, 1, 0, 1);
7689
11/12
✓ Branch 0 taken 4283398 times.
✓ Branch 1 taken 151954218 times.
✓ Branch 2 taken 151705084 times.
✓ Branch 3 taken 249134 times.
✓ Branch 4 taken 249134 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 139834818 times.
✓ Branch 7 taken 11870266 times.
✓ Branch 8 taken 11735324 times.
✓ Branch 9 taken 134942 times.
✓ Branch 10 taken 108821 times.
✓ Branch 11 taken 26121 times.
307942700 dopos(0,-1, 0, 1);
7690 #ifdef _MSC_VER
7691 #pragma warning(default:4127)
7692 #endif
7693
7694
4/4
✓ Branch 0 taken 152036140 times.
✓ Branch 1 taken 4201476 times.
✓ Branch 2 taken 3029458 times.
✓ Branch 3 taken 149006682 times.
156237616 if((b < 61) && (data[first + 1] == val))
7695 {
7696 149006682 b += 2;
7697 149006682 first++;
7698 149006682 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7f];
7699
7700 #ifdef _MSC_VER
7701 #pragma warning(disable:4127)
7702 #endif
7703
5/6
✓ Branch 0 taken 5963529 times.
✓ Branch 1 taken 143043153 times.
✓ Branch 2 taken 134561878 times.
✓ Branch 3 taken 8481275 times.
✓ Branch 4 taken 8481275 times.
✗ Branch 5 not taken.
283568560 dopos(-1, 0, 0, 0);
7704
5/6
✓ Branch 0 taken 3991529 times.
✓ Branch 1 taken 145015153 times.
✓ Branch 2 taken 99905321 times.
✓ Branch 3 taken 45109832 times.
✓ Branch 4 taken 45109832 times.
✗ Branch 5 not taken.
248912003 dopos(1, 0, 0, 0);
7705
5/6
✓ Branch 0 taken 4145912 times.
✓ Branch 1 taken 144860770 times.
✓ Branch 2 taken 141220031 times.
✓ Branch 3 taken 3640739 times.
✓ Branch 4 taken 3640739 times.
✗ Branch 5 not taken.
290226713 dopos(0,-1, 0, 0);
7706
5/6
✓ Branch 0 taken 5274234 times.
✓ Branch 1 taken 143732448 times.
✓ Branch 2 taken 32545435 times.
✓ Branch 3 taken 111187013 times.
✓ Branch 4 taken 111187013 times.
✗ Branch 5 not taken.
181552117 dopos(0, 1, 0, 0);
7707 #ifdef _MSC_VER
7708 #pragma warning(default:4127)
7709 #endif
7710
7711 149006682 first--;
7712 149006682 }
7713
7714 156237616 i = first;
7715 156237616 first = next[first];
7716 156237616 next[i] = UNUSED;
7717 156237616 }
7718
7719 156244017 count++;
7720
7721
2/2
✓ Branch 0 taken 154139440 times.
✓ Branch 1 taken 2104577 times.
156244017 if(count == (cbcount+1)*AVERAGE_COUNT/256)
7722 {
7723
2/2
✓ Branch 0 taken 7169 times.
✓ Branch 1 taken 2097408 times.
2104577 if(cbcount < 256)
7724 {
7725
1/2
✓ Branch 0 taken 2097408 times.
✗ Branch 1 not taken.
2097408 if(callback)
7726 callback(cbcount);
7727
7728 2097408 cbcount++;
7729 2097408 }
7730 2104577 }
7731 }
7732
7733
1/2
✓ Branch 0 taken 8193 times.
✗ Branch 1 not taken.
8193 if(callback)
7734 while(cbcount < 256)
7735 callback(cbcount++);
7736 8193 }
7737
7738 int32_t short_bmp_avg(BITMAP *bmp, int32_t i)
7739 {
7740 int32_t j=((int16_t *)bmp->line[0])[i];
7741 int32_t r=getr15(j);
7742 int32_t g=getg15(j);
7743 int32_t b=getb15(j);
7744 int32_t k=1;
7745
7746 if(i>0)
7747 {
7748 j=((int16_t *)bmp->line[0])[i-1];
7749 r+=getr15(j);
7750 g+=getg15(j);
7751 b+=getb15(j);
7752 ++k;
7753 }
7754
7755 if(i<(bmp->w-2))
7756 {
7757 j=((int16_t *)bmp->line[0])[i+1];
7758 r+=getr15(j);
7759 g+=getg15(j);
7760 b+=getb15(j);
7761 ++k;
7762 }
7763
7764 r/=k;
7765 g/=k;
7766 b/=k;
7767 return makecol15(r, g, b);
7768 }
7769
7770 // A consistent RENG (random enough number generator) for dither_rect()
7771 static uint16_t lfsr;
7772
7773 void lfsrInit()
7774 {
7775 lfsr=1;
7776 }
7777
7778 uint16_t lfsrNext()
7779 {
7780 auto bits=(lfsr^(lfsr>>2)^(lfsr>>3)^(lfsr>>5))&1;
7781 lfsr=(lfsr>>1)|(bits<<15);
7782 return lfsr;
7783 }
7784
7785 void dither_rect(BITMAP *bmp, PALETTE *pal, int32_t x1, int32_t y1, int32_t x2, int32_t y2,
7786 int32_t src_color1, int32_t src_color2, uint8_t dest_color1,
7787 uint8_t dest_color2)
7788 {
7789 BITMAP *src_bmp=create_bitmap_ex(15, abs(x2-x1)+1, 1);
7790 BITMAP *dest_bmp=create_bitmap_ex(8, abs(x2-x1)+1, abs(y2-y1)+1);
7791 int32_t r, g, b, direction=1;
7792 int32_t c;
7793 int32_t r1, r2, g1, g2, b1, b2;
7794 int32_t (*diff[2])[3];
7795 diff[0] = new int32_t[x2-x1+3][3];
7796 diff[1] = new int32_t[x2-x1+3][3];
7797 int32_t cdiff[3];
7798 RGB_MAP table;
7799 int32_t temp;
7800 int32_t red_rand_strength=0, green_rand_strength=0, blue_rand_strength=0;
7801
7802 lfsrInit();
7803 clear_bitmap(dest_bmp);
7804
7805 if(x1>x2)
7806 {
7807 temp=x1;
7808 x1=x2;
7809 x2=temp;
7810 }
7811
7812 if(y1>y2)
7813 {
7814 temp=y1;
7815 y1=y2;
7816 y2=temp;
7817 }
7818
7819 if(src_color1>src_color2)
7820 {
7821 temp=src_color1;
7822 src_color1=src_color2;
7823 src_color2=temp;
7824 }
7825
7826 if(dest_color1>dest_color2)
7827 {
7828 temp=dest_color1;
7829 dest_color1=dest_color2;
7830 dest_color2=temp;
7831 }
7832
7833 create_rgb_table_range(&table, *pal, dest_color1, dest_color2, NULL);
7834 r1=getr15(src_color1);
7835 r2=getr15(src_color2);
7836 g1=getg15(src_color1);
7837 g2=getg15(src_color2);
7838 b1=getb15(src_color1);
7839 b2=getb15(src_color2);
7840 red_rand_strength=getr8(dest_color1+1)-getr8(dest_color1);
7841 green_rand_strength=getg8(dest_color1+1)-getg8(dest_color1);
7842 blue_rand_strength=getb8(dest_color1+1)-getb8(dest_color1);
7843 memset(cdiff,0,3*sizeof(float));
7844 memset(diff[0],0,(x2-x1+3)*3*sizeof(int32_t));
7845 memset(diff[1],0,(x2-x1+3)*3*sizeof(int32_t));
7846 int32_t mc, mr, mg, mb;
7847
7848 for(int32_t i=0; i<src_bmp->w; i++)
7849 {
7850 r = mix_value(r1, r2, i, src_bmp->w-1);
7851 g = mix_value(g1, g2, i, src_bmp->w-1);
7852 b = mix_value(b1, b2, i, src_bmp->w-1);
7853 c = makecol15(r,g,b);
7854 ((int16_t *)src_bmp->line[0])[i] = c;
7855 }
7856
7857 uint8_t tempcolor, origcolor;
7858
7859 for(int32_t j=0; j<=y2-y1; ++j)
7860 {
7861 if(direction==1)
7862 {
7863 for(int32_t i=0; i<=x2-x1; ++i)
7864 {
7865 mc=((int16_t *)src_bmp->line[0])[i];
7866 mr=bound(getr15(mc)+lfsrNext()%(red_rand_strength*2+1)-(red_rand_strength*1),0,255);
7867 mg=bound(getg15(mc)+lfsrNext()%(green_rand_strength*2+1)-(green_rand_strength*1),0,255);
7868 mb=bound(getb15(mc)+lfsrNext()%(blue_rand_strength*2+1)-(blue_rand_strength*1),0,255);
7869 cdiff[0]=bound(mr+
7870 diff[0][i][0]+
7871 diff[0][i+1][0]+
7872 diff[0][i+2][0]+
7873 cdiff[0],0,255);
7874 cdiff[1]=bound(mg+
7875 diff[0][i][1]+
7876 diff[0][i+1][1]+
7877 diff[0][i+2][1]+
7878 cdiff[1],0,255);
7879 cdiff[2]=bound(mb+
7880 diff[0][i][2]+
7881 diff[0][i+1][2]+
7882 diff[0][i+2][2]+
7883 cdiff[2],0,255);
7884 // bmp->line[j][i+x1]=bound(makecol8_map(int32_t(cdiff[0]),int32_t(cdiff[1]),int32_t(cdiff[2]),&table),dest_color1,dest_color2);
7885 origcolor=makecol8_map(mr,mg,mb,&table);
7886 // tempcolor=bound(makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table),origcolor-1,origcolor+1);
7887 tempcolor=makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table);
7888 dest_bmp->line[j][i]=tempcolor;
7889 r=getr8(tempcolor);
7890 g=getg8(tempcolor);
7891 b=getb8(tempcolor);
7892 diff[1][i][0]=(cdiff[0]-r)*3/16;
7893 diff[1][i][1]=(cdiff[1]-g)*3/16;
7894 diff[1][i][2]=(cdiff[2]-b)*3/16;
7895 diff[1][i+1][0]=(cdiff[0]-r)*5/16;
7896 diff[1][i+1][1]=(cdiff[1]-g)*5/16;
7897 diff[1][i+1][2]=(cdiff[2]-b)*5/16;
7898 diff[1][i+2][0]=(cdiff[0]-r)*1/16;
7899 diff[1][i+2][1]=(cdiff[1]-g)*1/16;
7900 diff[1][i+2][2]=(cdiff[2]-b)*1/16;
7901 cdiff[0]=(cdiff[0]-r)*7/16;
7902 cdiff[1]=(cdiff[1]-g)*7/16;
7903 cdiff[2]=(cdiff[2]-b)*7/16;
7904 }
7905
7906 memcpy(diff[0],diff[1],(x2-x1+3)*3*sizeof(int32_t));
7907 memset(diff[1],0,(x2-x1+3)*3*sizeof(int32_t));
7908 direction=-1;
7909 }
7910 else
7911 {
7912 for(int32_t i=x2-x1; i>=0; --i)
7913 {
7914 mc=((int16_t *)src_bmp->line[0])[i];
7915 mr=getr15(mc);
7916 mg=getg15(mc);
7917 mb=getb15(mc);
7918 cdiff[0]=bound(mr+
7919 diff[0][i][0]+
7920 diff[0][i+1][0]+
7921 diff[0][i+2][0]+
7922 cdiff[0],0,255);
7923 cdiff[1]=bound(mg+
7924 diff[0][i][1]+
7925 diff[0][i+1][1]+
7926 diff[0][i+2][1]+
7927 cdiff[1],0,255);
7928 cdiff[2]=bound(mb+
7929 diff[0][i][2]+
7930 diff[0][i+1][2]+
7931 diff[0][i+2][2]+
7932 cdiff[2],0,255);
7933 // bmp->line[j][i+x1]=bound(makecol8_map(int32_t(cdiff[0]),int32_t(cdiff[1]),int32_t(cdiff[2]),&table),dest_color1,dest_color2);
7934 origcolor=makecol8_map(mr,mg,mb,&table);
7935 // tempcolor=bound(makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table),origcolor-1,origcolor+1);
7936 tempcolor=makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table);
7937 dest_bmp->line[j][i]=tempcolor;
7938 r=getr8(tempcolor);
7939 g=getg8(tempcolor);
7940 b=getb8(tempcolor);
7941 diff[1][i][0]=(cdiff[0]-r)*3/16;
7942 diff[1][i][1]=(cdiff[1]-g)*3/16;
7943 diff[1][i][2]=(cdiff[2]-b)*3/16;
7944 diff[1][i+1][0]=(cdiff[0]-r)*5/16;
7945 diff[1][i+1][1]=(cdiff[1]-g)*5/16;
7946 diff[1][i+1][2]=(cdiff[2]-b)*5/16;
7947 diff[1][i+2][0]=(cdiff[0]-r)*1/16;
7948 diff[1][i+2][1]=(cdiff[1]-g)*1/16;
7949 diff[1][i+2][2]=(cdiff[2]-b)*1/16;
7950 cdiff[0]=(cdiff[0]-r)*7/16;
7951 cdiff[1]=(cdiff[1]-g)*7/16;
7952 cdiff[2]=(cdiff[2]-b)*7/16;
7953 }
7954
7955 memcpy(diff[0],diff[1],(x2-x1+3)*3*sizeof(float));
7956 memset(diff[1],0,(x2-x1+3)*3*sizeof(float));
7957 direction=1;
7958 }
7959 }
7960
7961 blit(dest_bmp, bmp, 0, 0, x1, y1, x2-x1+1, y2-y1+1);
7962 delete[] diff[1];
7963 delete[] diff[0];
7964 destroy_bitmap(src_bmp);
7965 destroy_bitmap(dest_bmp);
7966 return;
7967 }
7968
7969 bool do_text_button(int32_t x,int32_t y,int32_t w,int32_t h,const char *text)
7970 {
7971 bool over=false;
7972
7973 while(gui_mouse_b())
7974 {
7975 if(mouse_in_rect(x,y,w,h))
7976 {
7977 if(!over)
7978 {
7979 vsync();
7980 jwin_draw_text_button(screen, x, y, w, h, text, D_SELECTED, true);
7981 over=true;
7982 update_hw_screen();
7983 }
7984 }
7985 else
7986 {
7987 if(over)
7988 {
7989 vsync();
7990 jwin_draw_text_button(screen, x, y, w, h, text, 0, true);
7991 over=false;
7992 update_hw_screen();
7993 }
7994 }
7995 rest(1);
7996 }
7997
7998 return over;
7999 }
8000
8001 bool do_text_button_reset(int32_t x,int32_t y,int32_t w,int32_t h,const char *text)
8002 {
8003 bool over=false;
8004
8005 while(gui_mouse_b())
8006 {
8007 //vsync();
8008 if(mouse_in_rect(x,y,w,h))
8009 {
8010 if(!over)
8011 {
8012 vsync();
8013 jwin_draw_text_button(screen, x, y, w, h, text, D_SELECTED, true);
8014 over=true;
8015
8016 update_hw_screen();
8017 }
8018 }
8019 else
8020 {
8021 if(over)
8022 {
8023 vsync();
8024 jwin_draw_text_button(screen, x, y, w, h, text, 0, true);
8025 over=false;
8026
8027 update_hw_screen();
8028 }
8029 }
8030 rest(1);
8031 }
8032
8033 if(over)
8034 {
8035 vsync();
8036 jwin_draw_text_button(screen, x, y, w, h, text, 0, true);
8037
8038 update_hw_screen();
8039 }
8040
8041 return over;
8042 }
8043 bool do_icon_button_reset(int32_t x,int32_t y,int32_t w,int32_t h,int icon)
8044 {
8045 bool over=false;
8046
8047 while(gui_mouse_b())
8048 {
8049 //vsync();
8050 if(mouse_in_rect(x,y,w,h))
8051 {
8052 if(!over)
8053 {
8054 vsync();
8055 jwin_draw_icon_button(screen, x, y, w, h, icon, D_SELECTED, true);
8056 over=true;
8057
8058 update_hw_screen();
8059 }
8060 }
8061 else
8062 {
8063 if(over)
8064 {
8065 vsync();
8066 jwin_draw_icon_button(screen, x, y, w, h, icon, 0, true);
8067 over=false;
8068
8069 update_hw_screen();
8070 }
8071 }
8072 rest(1);
8073 }
8074
8075 if(over)
8076 {
8077 vsync();
8078 jwin_draw_icon_button(screen, x, y, w, h, icon, 0, true);
8079
8080 update_hw_screen();
8081 }
8082
8083 return over;
8084 }
8085
8086 int32_t jwin_tab_proc(int32_t msg, DIALOG *d, int32_t c)
8087 {
8088 int32_t i;
8089 int32_t tx;
8090 int32_t sd=2; //selected delta
8091 TABPANEL *panel=(TABPANEL *)d->dp;
8092 DIALOG *panel_dialog=NULL, *current_object=NULL;
8093 int32_t selected=0;
8094 int32_t counter=0;
8095 ASSERT(d);
8096 int32_t temp_d, temp_d2;
8097
8098 if(d->dp==NULL) return D_O_K;
8099
8100 panel_dialog=(DIALOG *)d->dp3;
8101
8102 if (msg != MSG_START && msg != MSG_END)
8103 {
8104 bool redraw = false;
8105 for (i = 0; panel[i].text; ++i)
8106 {
8107 if ((panel[i].flags & D_SELECTED) && !(d->flags & D_HIDDEN))
8108 {
8109 for (counter = 0; counter < panel[i].objects; counter++)
8110 {
8111 current_object = panel_dialog + (panel[i].dialog[counter]);
8112 current_object->flags &= ~D_HIDDEN;
8113 if (object_message(current_object, MSG_IDLE, 0) & D_REDRAW)
8114 redraw = true;
8115 }
8116 }
8117 else
8118 {
8119 for (counter = 0; counter < panel[i].objects; counter++)
8120 {
8121 current_object = panel_dialog + (panel[i].dialog[counter]);
8122 current_object->flags |= D_HIDDEN;
8123 if (object_message(current_object, MSG_IDLE, 0) & D_REDRAW)
8124 redraw = true;
8125 }
8126 }
8127
8128 /*if (d->flags & D_HIDDEN)
8129 {
8130 for(counter=0; counter<panel[i].objects; counter++)
8131 {
8132 current_object=panel_dialog+(panel[i].dialog[counter]);
8133 current_object->x=zq_screen_w*3;
8134 current_object->y=zq_screen_h*3;
8135 }
8136 }*/
8137 }
8138 if (redraw)
8139 broadcast_dialog_message(MSG_DRAW, 0);
8140 }
8141 FONT *oldfont = font;
8142 switch(msg)
8143 {
8144 case MSG_DRAW:
8145 {
8146 if(d->x<zq_screen_w&&d->y<zq_screen_h)
8147 {
8148 if(d->dp2)
8149 {
8150 font = (FONT *)d->dp2;
8151 }
8152
8153 panel_dialog=(DIALOG *)d->dp3;
8154 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+8+text_height(font), scheme[jcBOX]); //tab area
8155 rectfill(screen, d->x+1, d->y+sd+text_height(font)+7, d->x+d->w-2, d->y+sd+d->h-2, scheme[jcBOX]); //panel
8156 vline(screen, d->x, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcLIGHT]);
8157 vline(screen, d->x+1, d->y+sd+7+text_height(font), d->y+sd+d->h-3, scheme[jcMEDLT]);
8158 vline(screen, d->x+d->w-2, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcMEDDARK]);
8159 vline(screen, d->x+d->w-1, d->y+sd+7+text_height(font)-1, d->y+sd+d->h-1, scheme[jcDARK]);
8160 hline(screen, d->x+1, d->y+sd+d->h-2, d->x+d->w-3, scheme[jcMEDDARK]);
8161 hline(screen, d->x, d->y+sd+d->h-1, d->x+d->w-2, scheme[jcDARK]);
8162 tx=d->x;
8163
8164 if(d->dp)
8165 {
8166 if(!(panel[((d->d1&0xFF00)>>8)].flags&D_SELECTED))
8167 {
8168 hline(screen, tx+1, d->y+sd+6+text_height(font)+1, tx+2, scheme[jcMEDLT]); //initial bottom
8169 hline(screen, tx, d->y+sd+6+text_height(font), tx+1, scheme[jcLIGHT]); //initial bottom
8170 }
8171
8172 tx+=2;
8173
8174 for(i=0; panel[i].text; ++i)
8175 {
8176 if(panel[i].flags&D_SELECTED)
8177 {
8178 selected=i;
8179 }
8180 }
8181
8182 for(i=((d->d1&0xFF00)>>8); panel[i].text&&i<=last_visible_tab(panel,((d->d1&0xFF00)>>8),d->w); ++i)
8183 {
8184 sd=(panel[i].flags&D_SELECTED)?0:2;
8185
8186 if((i==((d->d1&0xFF00)>>8)) || (!(panel[i-1].flags&D_SELECTED)))
8187 {
8188 vline(screen, tx-(2-sd), d->y+sd+2, d->y+8+text_height(font), scheme[jcLIGHT]); //left side
8189 vline(screen, tx-(2-sd)+1, d->y+sd+2, d->y+8+text_height(font), scheme[jcMEDLT]); //left side
8190 putpixel(screen, tx+1-(2-sd), d->y+sd+1, scheme[jcLIGHT]); //left angle
8191 }
8192
8193 hline(screen, tx+2-(2-sd), d->y+sd, tx+12+(2-sd)+text_length(font, (char *)panel[i].text), scheme[jcLIGHT]); //top
8194 hline(screen, tx+2-(2-sd), d->y+sd+1, tx+12+(2-sd)+text_length(font, (char *)panel[i].text), scheme[jcMEDLT]); //top
8195
8196 if(!(panel[i].flags&D_SELECTED))
8197 {
8198 hline(screen, tx+1, d->y+sd+6+text_height(font), tx+13+text_length(font, (char *)panel[i].text)+1, scheme[jcLIGHT]); //bottom
8199 hline(screen, tx, d->y+sd+6+text_height(font)+1, tx+13+text_length(font, (char *)panel[i].text)+1, scheme[jcMEDLT]); //bottom
8200 }
8201
8202 tx+=4;
8203 gui_textout_ln(screen, (uint8_t*)panel[i].text, tx+4, d->y+sd+4, scheme[jcBOXFG], scheme[jcBOX], 0);
8204 tx+=text_length(font, (char *)panel[i].text)+10;
8205
8206 if(!(panel[i+1].text) || (!(panel[i+1].flags&D_SELECTED)))
8207 {
8208 putpixel(screen, tx-1+(2-sd), d->y+sd+1, scheme[jcDARK]); //right angle
8209 vline(screen, tx+(2-sd), d->y+sd+2, d->y+8+text_height(font)-1, scheme[jcDARK]); //right side
8210 vline(screen, tx+(2-sd)-1, d->y+sd+2, d->y+8+text_height(font)-(sd?1:0), scheme[jcMEDDARK]); //right side
8211 }
8212
8213 tx++;
8214 }
8215
8216 if(((d->d1&0xFF00)>>8)!=0||last_visible_tab(panel,((d->d1&0xFF00)>>8),d->w)+1<tab_count(panel))
8217 {
8218 jwin_draw_icon_button(screen,d->x+d->w-14,d->y+2, 14, 14, BTNICON_ARROW_RIGHT, 0, true);
8219 jwin_draw_icon_button(screen,d->x+d->w-28,d->y+2, 14, 14, BTNICON_ARROW_LEFT, 0, true);
8220 }
8221 }
8222
8223 if((tx+(2-sd))<(d->x+d->w))
8224 {
8225 hline(screen, tx+(2-sd)-1, d->y+8+text_height(font), d->x+d->w-1, scheme[jcLIGHT]); //ending bottom
8226 hline(screen, tx+(2-sd)-2, d->y+8+text_height(font)+1, d->x+d->w-2, scheme[jcMEDLT]); //ending bottom
8227 }
8228
8229 font = oldfont;
8230
8231 //what dialog is this tab control in (programmer must set manually)
8232 panel_dialog=(DIALOG *)d->dp3;
8233
8234 //for each object handled by the currently selected tab...
8235 for(counter=0; counter<panel[selected].objects; counter++)
8236 {
8237 //assign current_object to one of the controls handled by the tab
8238 current_object=panel_dialog+(panel[selected].dialog[counter]);
8239 //remember the x and y positions of the control
8240 current_object->x=panel[selected].xy[counter*2];
8241 current_object->y=panel[selected].xy[counter*2+1];
8242 object_message(current_object, MSG_DRAW, 0);
8243 }
8244
8245 //if there was a previously selected tab...
8246 if((d->d1&0x00FF)!=0x00FF)
8247 {
8248 //for each object handled by the tab
8249 for(counter=0; counter<panel[d->d1&0xFF].objects; counter++)
8250 {
8251 //assign current_object to one of the controls handled by the tab
8252 current_object=panel_dialog+(panel[d->d1&0xFF].dialog[counter]);
8253 // //remember the x and y positions of the control
8254 // panel[d->d1].xy[counter*2]=current_object->x;
8255 // panel[d->d1].xy[counter*2+1]=current_object->y;
8256 current_object->x=zq_screen_w*3;
8257 current_object->y=zq_screen_h*3;
8258 }
8259 }
8260 }
8261 }
8262 break;
8263
8264 case MSG_CLICK:
8265 {
8266 d->d1&=0xFF00;
8267 d->d1|=0x00FF;
8268 if(d->dp2)
8269 {
8270 font = (FONT *)d->dp2;
8271 }
8272
8273 // is the mouse on one of the tab arrows (if visible) or in the tab area?
8274 if(uses_tab_arrows(panel, d->w)&&(mouse_in_rect(d->x+d->w-28, d->y+2, 28, 14)))
8275 {
8276 if(mouse_in_rect(d->x+d->w-28, d->y+2, 14, 14))
8277 {
8278 if(do_icon_button_reset(d->x+d->w-28, d->y+2, 14, 14, BTNICON_ARROW_LEFT))
8279 {
8280 temp_d=((d->d1&0xFF00)>>8);
8281 temp_d2=(d->d1&0x00FF);
8282
8283 if(temp_d>0)
8284 {
8285 --temp_d;
8286 }
8287
8288 d->d1=(temp_d<<8)|temp_d2;
8289 d->flags|=D_DIRTY;
8290 }
8291 }
8292 else if(mouse_in_rect(d->x+d->w-14, d->y+2, 14, 14))
8293 {
8294 if(do_icon_button_reset(d->x+d->w-14, d->y+2, 14, 14, BTNICON_ARROW_RIGHT))
8295 {
8296 temp_d=((d->d1&0xFF00)>>8);
8297 temp_d2=(d->d1&0x00FF);
8298
8299 if(last_visible_tab(panel, temp_d, d->w)<(tab_count(panel)-1))
8300 {
8301 ++temp_d;
8302 }
8303
8304 d->d1=(temp_d<<8)|temp_d2;
8305 d->flags|=D_DIRTY;
8306 }
8307 }
8308 }
8309 else
8310 {
8311 d_tab_proc(msg, d, c);
8312 }
8313 font = oldfont;
8314 jwin_tab_proc(MSG_IDLE,d,0);
8315 }
8316 break;
8317
8318 default:
8319 return d_tab_proc(msg, d, c);
8320 break;
8321 }
8322
8323 panel_dialog=(DIALOG *)d->dp3;
8324
8325 if(d->flags & D_HIDDEN)
8326 {
8327 for(i=0; panel[i].text; ++i)
8328 {
8329 for(counter=0; counter<panel[i].objects; counter++)
8330 {
8331 current_object=panel_dialog+(panel[i].dialog[counter]);
8332 current_object->x=zq_screen_w*3;
8333 current_object->y=zq_screen_h*3;
8334 }
8335 }
8336
8337 //d->x=zq_screen_w*3;
8338 //d->y=zq_screen_h*3;
8339 }
8340 else
8341 {
8342 for(i=0; panel[i].text; ++i)
8343 {
8344 for(counter=0; counter<panel[i].objects; counter++)
8345 {
8346 current_object=panel_dialog+(panel[i].dialog[counter]);
8347 current_object->x=panel[i].xy[counter*2];
8348 current_object->y=panel[i].xy[counter*2+1];
8349 }
8350 }
8351
8352 // d->x=zq_screen_w*3;
8353 //d->y=zq_screen_h*3;
8354 }
8355
8356 return broadcast_dialog_message(MSG_IDLE, 0);
8357
8358 // return D_O_K;
8359 }
8360
8361 int32_t discern_tab(GUI::TabPanel *panel, int32_t first_tab, int32_t x)
8362 {
8363 int32_t w=0;
8364
8365 for(size_t i=first_tab; i < panel->getSize(); i++)
8366 {
8367 w+=text_length(font, panel->getName(i))+15;
8368
8369 if(w>x)
8370 {
8371 return i;
8372 }
8373 }
8374
8375 return -1;
8376 }
8377 int32_t tabs_width(GUI::TabPanel *panel)
8378 {
8379 int32_t w=0;
8380
8381 for(size_t i=0; i < panel->getSize(); ++i)
8382 {
8383 w+=text_length(font, panel->getName(i))+15;
8384 }
8385
8386 return w+1;
8387 }
8388 bool uses_tab_arrows(GUI::TabPanel *panel, int32_t maxwidth)
8389 {
8390 return (tabs_width(panel)>maxwidth);
8391 }
8392 size_t last_visible_tab(GUI::TabPanel *panel, int32_t first_tab, int32_t maxwidth)
8393 {
8394 size_t i;
8395 int32_t w=0;
8396
8397 if(uses_tab_arrows(panel, maxwidth))
8398 {
8399 maxwidth-=28;
8400 }
8401
8402 for(i=first_tab; i < panel->getSize(); ++i)
8403 {
8404 w+=text_length(font, panel->getName(i))+15;
8405
8406 if(w>maxwidth)
8407 {
8408 return i-1;
8409 }
8410 }
8411
8412 return i-1;
8413 }
8414 int32_t displayed_tabs_width(GUI::TabPanel *panel, int32_t first_tab, int32_t maxwidth)
8415 {
8416 size_t i=0;
8417 int32_t w=0;
8418
8419 for(i=first_tab; i<=last_visible_tab(panel, first_tab, maxwidth); ++i)
8420 {
8421 w+=text_length(font, panel->getName(i))+15;
8422 }
8423
8424 return w+1;
8425 }
8426
8427 INLINE int32_t is_in_rect(int32_t x,int32_t y,int32_t rx1,int32_t ry1,int32_t rx2,int32_t ry2)
8428 {
8429 return x>=rx1 && x<=rx2 && y>=ry1 && y<=ry2;
8430 }
8431
8432 int32_t new_tab_proc(int32_t msg, DIALOG *d, int32_t c)
8433 {
8434 assert(d->flags&D_NEW_GUI);
8435
8436 int32_t tx;
8437 int32_t ret = D_O_K;
8438 int32_t sd=2; //selected delta
8439 static bool skipredraw = false;
8440 GUI::TabPanel *panel=(GUI::TabPanel*)d->dp;
8441 ASSERT(d);
8442
8443 if(d->dp==NULL) return D_O_K;
8444
8445 FONT *oldfont = font;
8446 if(d->dp2)
8447 {
8448 font = (FONT *)d->dp2;
8449 }
8450
8451 switch(msg)
8452 {
8453 case MSG_DRAW:
8454 {
8455 if(skipredraw)
8456 {
8457 skipredraw = false;
8458 ret = D_REDRAW;
8459 break;
8460 }
8461 if(d->x<zq_screen_w&&d->y<zq_screen_h)
8462 {
8463 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+8+text_height(font), scheme[jcBOX]); //tab area
8464 rectfill(screen, d->x+1, d->y+sd+text_height(font)+7, d->x+d->w-2, d->y+sd+d->h-2, scheme[jcBOX]); //panel
8465 vline(screen, d->x, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcLIGHT]);
8466 vline(screen, d->x+1, d->y+sd+7+text_height(font), d->y+sd+d->h-3, scheme[jcMEDLT]);
8467 vline(screen, d->x+d->w-2, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcMEDDARK]);
8468 vline(screen, d->x+d->w-1, d->y+sd+7+text_height(font)-1, d->y+sd+d->h-1, scheme[jcDARK]);
8469 hline(screen, d->x+1, d->y+sd+d->h-2, d->x+d->w-3, scheme[jcMEDDARK]);
8470 hline(screen, d->x, d->y+sd+d->h-1, d->x+d->w-2, scheme[jcDARK]);
8471 tx=d->x;
8472
8473 if(d->dp)
8474 {
8475 if(panel->getCurrentIndex() != d->d1)
8476 {
8477 hline(screen, tx+1, d->y+sd+6+text_height(font)+1, tx+2, scheme[jcMEDLT]); //initial bottom
8478 hline(screen, tx, d->y+sd+6+text_height(font), tx+1, scheme[jcLIGHT]); //initial bottom
8479 }
8480
8481 tx+=2;
8482
8483 for(size_t i=d->d1; i < panel->getSize()&&i<=last_visible_tab(panel,d->d1,d->w); ++i)
8484 {
8485 sd=(i==panel->getCurrentIndex())?0:2;
8486
8487 if((i==d->d1) || (i-1 != panel->getCurrentIndex()))
8488 {
8489 vline(screen, tx-(2-sd), d->y+sd+2, d->y+8+text_height(font), scheme[jcLIGHT]); //left side
8490 vline(screen, tx-(2-sd)+1, d->y+sd+2, d->y+8+text_height(font), scheme[jcMEDLT]); //left side
8491 putpixel(screen, tx+1-(2-sd), d->y+sd+1, scheme[jcLIGHT]); //left angle
8492 }
8493
8494 hline(screen, tx+2-(2-sd), d->y+sd, tx+12+(2-sd)+text_length(font, panel->getName(i)), scheme[jcLIGHT]); //top
8495 hline(screen, tx+2-(2-sd), d->y+sd+1, tx+12+(2-sd)+text_length(font, panel->getName(i)), scheme[jcMEDLT]); //top
8496
8497 if(i!=panel->getCurrentIndex())
8498 {
8499 hline(screen, tx+1, d->y+sd+6+text_height(font), tx+13+text_length(font, panel->getName(i))+1, scheme[jcLIGHT]); //bottom
8500 hline(screen, tx, d->y+sd+6+text_height(font)+1, tx+13+text_length(font, panel->getName(i))+1, scheme[jcMEDLT]); //bottom
8501 }
8502 else if(d->flags & D_GOTFOCUS)
8503 {
8504 hline(screen, tx+1, d->y+sd+6+text_height(font), tx+13+text_length(font, panel->getName(i))+1, scheme[jcBOXFG]); //bottom
8505 hline(screen, tx, d->y+sd+6+text_height(font)+1, tx+13+text_length(font, panel->getName(i))+1, scheme[jcBOXFG]); //bottom
8506 }
8507
8508 tx+=4;
8509 uint8_t* pname = (uint8_t*)(panel->getName(i));
8510 bool dis = panel->getDisabled(i);
8511 if(dis)
8512 gui_textout_ln(screen, pname, tx+5, d->y+sd+5, scheme[jcLIGHT], scheme[jcBOX], 0);
8513 gui_textout_ln(screen, pname, tx+4, d->y+sd+4, scheme[dis ? jcDISABLED_FG : jcBOXFG], dis ? -1 : scheme[jcBOX], 0);
8514 tx+=text_length(font, (const char*)pname)+10;
8515
8516 if((i+1>=panel->getSize()) || (i+1!=panel->getCurrentIndex()))
8517 {
8518 putpixel(screen, tx-1+(2-sd), d->y+sd+1, scheme[jcDARK]); //right angle
8519 vline(screen, tx+(2-sd), d->y+sd+2, d->y+8+text_height(font)-1, scheme[jcDARK]); //right side
8520 vline(screen, tx+(2-sd)-1, d->y+sd+2, d->y+8+text_height(font)-(sd?1:0), scheme[jcMEDDARK]); //right side
8521 }
8522
8523 tx++;
8524 }
8525
8526 if(d->d1!=0||last_visible_tab(panel,d->d1,d->w)+1<panel->getSize())
8527 {
8528 jwin_draw_icon_button(screen,d->x+d->w-14,d->y+2, 14, 14, BTNICON_ARROW_RIGHT, 0, true);
8529 jwin_draw_icon_button(screen,d->x+d->w-28,d->y+2, 14, 14, BTNICON_ARROW_LEFT, 0, true);
8530 }
8531 }
8532
8533 if((tx+(2-sd))<(d->x+d->w))
8534 {
8535 hline(screen, tx+(2-sd)-1, d->y+8+text_height(font), d->x+d->w-1, scheme[jcLIGHT]); //ending bottom
8536 hline(screen, tx+(2-sd)-2, d->y+8+text_height(font)+1, d->x+d->w-2, scheme[jcMEDLT]); //ending bottom
8537 }
8538
8539 }
8540 }
8541 break;
8542
8543 case MSG_WANTFOCUS:
8544 // if(gui_mouse_b())
8545 ret = D_WANTFOCUS|D_REDRAW;
8546 break;
8547 case MSG_GOTFOCUS:
8548 case MSG_LOSTFOCUS:
8549 skipredraw = true;
8550 break;
8551 case MSG_CHAR:
8552 {
8553 int32_t ind = panel->getCurrentIndex();
8554 auto oldind = ind;
8555 switch(c>>8)
8556 {
8557 case KEY_LEFT:
8558 do
8559 {
8560 if(ind > 0)
8561 {
8562 --ind;
8563 }
8564 else
8565 {
8566 ind = panel->getSize()-1;
8567 }
8568 }
8569 while(ind != oldind && panel->getDisabled(ind));
8570 break;
8571 case KEY_RIGHT:
8572 do
8573 {
8574 if(ind+1 < signed(panel->getSize()))
8575 {
8576 ++ind;
8577 }
8578 else
8579 {
8580 ind = 0;
8581 }
8582 }
8583 while(ind != oldind && panel->getDisabled(ind));
8584 break;
8585 default: ind = -1;
8586 }
8587 if(ind > -1 && ind != oldind)
8588 {
8589 panel->switchTo(ind);
8590 GUI_EVENT(d, geCHANGE_SELECTION);
8591 ret |= D_USED_CHAR;
8592 }
8593 }
8594 break;
8595
8596 case MSG_CLICK:
8597 {
8598 // is the mouse on one of the tab arrows (if visible) or in the tab area?
8599 if(uses_tab_arrows(panel, d->w)&&(mouse_in_rect(d->x+d->w-28, d->y+2, 28, 14)))
8600 {
8601 if(mouse_in_rect(d->x+d->w-28, d->y+2, 14, 14))
8602 {
8603 if(do_icon_button_reset(d->x+d->w-28, d->y+2, 14, 14, BTNICON_ARROW_LEFT))
8604 {
8605 if(d->d1>0)
8606 {
8607 --d->d1;
8608 }
8609
8610 ret |= D_REDRAW;
8611 }
8612 }
8613 else if(mouse_in_rect(d->x+d->w-14, d->y+2, 14, 14))
8614 {
8615 if(do_icon_button_reset(d->x+d->w-14, d->y+2, 14, 14, BTNICON_ARROW_RIGHT))
8616 {
8617 size_t t = last_visible_tab(panel, d->d1, d->w);
8618 if(t<(panel->getSize()-1))
8619 {
8620 while(t==last_visible_tab(panel, d->d1, d->w))
8621 ++d->d1;
8622 }
8623
8624 ret |= D_REDRAW;
8625 }
8626 }
8627 }
8628 else if(is_in_rect(gui_mouse_x(),gui_mouse_y(), d->x+2, d->y+2, d->x+displayed_tabs_width(panel,((d->d1&0xFF00)>>8),d->w), d->y+text_height(font)+9))
8629 {
8630 // find out what the new tab (tb) will be (where the mouse is)
8631 int32_t newtab = discern_tab(panel, d->d1, gui_mouse_x()-d->x-2);
8632 if(newtab > -1 && newtab != panel->getCurrentIndex() && !panel->getDisabled(newtab))
8633 {
8634 panel->switchTo(newtab);
8635 GUI_EVENT(d, geCHANGE_SELECTION);
8636 }
8637 }
8638 }
8639 break;
8640 }
8641 font = oldfont;
8642 return ret;
8643 }
8644
8645
8646
8647
8648 int32_t jwin_hline_proc(int32_t msg, DIALOG *d, int32_t)
8649 {
8650 ASSERT(d);
8651
8652 if(msg==MSG_DRAW)
8653 {
8654 if(d->w < 1) return D_O_K;
8655 for(int q = 0; q <= d->d1; ++q)
8656 {
8657 if(d->d2&1)
8658 {
8659 hline(screen, d->x, d->y+q, d->x+d->w-1, d->fg);
8660 }
8661 else
8662 {
8663 hline(screen, d->x, d->y-q, d->x+d->w-1, scheme[jcMEDDARK]);
8664 hline(screen, d->x, d->y+1+q, d->x+d->w-1, scheme[jcLIGHT]);
8665 }
8666 }
8667 }
8668
8669 return D_O_K;
8670 }
8671
8672 int32_t jwin_vline_proc(int32_t msg, DIALOG *d, int32_t)
8673 {
8674 ASSERT(d);
8675
8676 if(msg==MSG_DRAW)
8677 {
8678 if(d->h < 1) return D_O_K;
8679 for(int q = 0; q <= d->d1; ++q)
8680 {
8681 if(d->d2&1)
8682 {
8683 vline(screen, d->x+q, d->y, d->y+d->h-1, d->fg);
8684 }
8685 else
8686 {
8687 vline(screen, d->x+q, d->y, d->y+d->h-1, scheme[jcMEDDARK]);
8688 vline(screen, d->x+1-q, d->y, d->y+d->h-1, scheme[jcLIGHT]);
8689 }
8690 }
8691 }
8692
8693 return D_O_K;
8694 }
8695
8696 int32_t jwin_editbox_proc(int32_t msg, DIALOG *d, int32_t c)
8697 {
8698 return d_editbox_proc(msg, d, c);
8699 }
8700
8701 //centers dialog based on first object, which should be the containing window
8702 3260 void jwin_center_dialog(DIALOG *dialog)
8703 {
8704 int32_t xc, yc;
8705 int32_t c;
8706 ASSERT(dialog);
8707
8708 /* how much to move by? */
8709 3260 xc = (zq_screen_w - dialog[0].w) / 2 - dialog[0].x;
8710 3260 yc = (zq_screen_h - dialog[0].h) / 2 - dialog[0].y;
8711
8712 /* move it */
8713
2/2
✓ Branch 0 taken 70779 times.
✓ Branch 1 taken 3260 times.
74039 for(c=0; dialog[c].proc; c++)
8714 {
8715 70779 dialog[c].x += xc;
8716 70779 dialog[c].y += yc;
8717 70779 }
8718 3260 }
8719 //up-left aligns dialog based on first object, which should be the containing window
8720 void jwin_ulalign_dialog(DIALOG *dialog)
8721 {
8722 int32_t xc, yc;
8723 int32_t c;
8724 ASSERT(dialog);
8725
8726 /* how much to move by? */
8727 xc = dialog[0].x;
8728 yc = dialog[0].y;
8729
8730 /* move it */
8731 for(c=0; dialog[c].proc; c++)
8732 {
8733 dialog[c].x -= xc;
8734 dialog[c].y -= yc;
8735 }
8736 }
8737
8738 //Custom slider proc
8739 int32_t d_jslider_proc(int32_t msg, DIALOG *d, int32_t c)
8740 {
8741 BITMAP *gui_bmp = screen;
8742 BITMAP *slhan = NULL;
8743 int32_t oldpos, newpos;
8744 int32_t sfg; /* slider foreground color */
8745 int32_t vert = TRUE; /* flag: is slider vertical? */
8746 int32_t hh = 7; /* handle height (width for horizontal sliders) */
8747 int32_t hmar; /* handle margin */
8748 int32_t slp; /* slider position */
8749 int32_t mp; /* mouse position */
8750 int32_t irange;
8751 int32_t slx, sly, slh, slw;
8752 int32_t msx, msy;
8753 int32_t retval = D_O_K;
8754 int32_t upkey, downkey;
8755 int32_t pgupkey, pgdnkey;
8756 int32_t homekey, endkey;
8757 int32_t delta;
8758 fixed slratio, slmax, slpos;
8759 typedef int32_t (*SLIDER_TYPE)(void*, int32_t);
8760 SLIDER_TYPE proc = NULL;
8761 //int32_t (*proc)(void *cbpointer, int32_t d2value);
8762 int32_t oldval;
8763 ASSERT(d);
8764
8765 /* check for slider direction */
8766 if(d->h < d->w)
8767 vert = FALSE;
8768
8769 /* set up the metrics for the control */
8770 if(d->dp != NULL)
8771 {
8772 slhan = (BITMAP *)d->dp;
8773
8774 if(vert)
8775 hh = slhan->h;
8776 else
8777 hh = slhan->w;
8778 }
8779
8780 hmar = hh/2;
8781 irange = (vert) ? d->h : d->w;
8782 slmax = itofix(irange-hh);
8783 slratio = slmax / (d->d1);
8784 slpos = slratio * d->d2;
8785 slp = fixtoi(slpos);
8786
8787 switch(msg)
8788 {
8789
8790 case MSG_DRAW:
8791 sfg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
8792
8793 if(vert)
8794 {
8795 rectfill(gui_bmp, d->x, d->y, d->x+d->w/2-2, d->y+d->h-1, d->bg);
8796 rectfill(gui_bmp, d->x+d->w/2-1, d->y, d->x+d->w/2+1, d->y+d->h-1, sfg);
8797 rectfill(gui_bmp, d->x+d->w/2+2, d->y, d->x+d->w-1, d->y+d->h-1, d->bg);
8798 }
8799 else
8800 {
8801 rectfill(gui_bmp, d->x, d->y, d->x+d->w-1, d->y+d->h/2-2, d->bg);
8802 rectfill(gui_bmp, d->x, d->y+d->h/2-1, d->x+d->w-1, d->y+d->h/2+1, sfg);
8803 rectfill(gui_bmp, d->x, d->y+d->h/2+2, d->x+d->w-1, d->y+d->h-1, d->bg);
8804 }
8805
8806 /* okay, background and slot are drawn, now draw the handle */
8807 if(slhan)
8808 {
8809 if(vert)
8810 {
8811 slx = d->x+(d->w/2)-(slhan->w/2);
8812 sly = d->y+(d->h-1)-(hh+slp);
8813 }
8814 else
8815 {
8816 slx = d->x+slp;
8817 sly = d->y+(d->h/2)-(slhan->h/2);
8818 }
8819
8820 draw_sprite(gui_bmp, slhan, slx, sly);
8821 }
8822 else
8823 {
8824 /* draw default handle */
8825 if(vert)
8826 {
8827 slx = d->x;
8828 sly = d->y+(d->h)-(hh+slp);
8829 slw = d->w-1;
8830 slh = hh-1;
8831 }
8832 else
8833 {
8834 slx = d->x+slp;
8835 sly = d->y;
8836 slw = hh-1;
8837 slh = d->h-1;
8838 }
8839
8840 /* draw body */
8841 rectfill(gui_bmp, slx+2, sly, slx+(slw-2), sly+slh, sfg);
8842 vline(gui_bmp, slx+1, sly+1, sly+slh-1, sfg);
8843 vline(gui_bmp, slx+slw-1, sly+1, sly+slh-1, sfg);
8844 vline(gui_bmp, slx, sly+2, sly+slh-2, sfg);
8845 vline(gui_bmp, slx+slw, sly+2, sly+slh-2, sfg);
8846 vline(gui_bmp, slx+1, sly+2, sly+slh-2, d->bg);
8847 hline(gui_bmp, slx+2, sly+1, slx+slw-2, d->bg);
8848 putpixel(gui_bmp, slx+2, sly+2, d->bg);
8849 }
8850
8851 if(d->flags & D_GOTFOCUS)
8852 dotted_rect(gui_bmp, d->x, d->y, d->x+d->w-1, d->y+d->h-1, sfg, d->bg);
8853
8854 break;
8855
8856 case MSG_WANTFOCUS:
8857 case MSG_LOSTFOCUS:
8858 return D_WANTFOCUS;
8859
8860 case MSG_KEY:
8861 if(!(d->flags & D_GOTFOCUS))
8862 return D_WANTFOCUS;
8863 else
8864 return D_O_K;
8865
8866 case MSG_CHAR:
8867 /* handle movement keys to move slider */
8868 c >>= 8;
8869
8870 if(vert)
8871 {
8872 upkey = KEY_UP;
8873 downkey = KEY_DOWN;
8874 pgupkey = KEY_PGUP;
8875 pgdnkey = KEY_PGDN;
8876 homekey = KEY_END;
8877 endkey = KEY_HOME;
8878 }
8879 else
8880 {
8881 upkey = KEY_RIGHT;
8882 downkey = KEY_LEFT;
8883 pgupkey = KEY_PGDN;
8884 pgdnkey = KEY_PGUP;
8885 homekey = KEY_HOME;
8886 endkey = KEY_END;
8887 }
8888
8889 if(c == upkey)
8890 delta = 1;
8891 else if(c == downkey)
8892 delta = -1;
8893 else if(c == pgdnkey)
8894 delta = -d->d1 / 16;
8895 else if(c == pgupkey)
8896 delta = d->d1 / 16;
8897 else if(c == homekey)
8898 delta = -d->d2;
8899 else if(c == endkey)
8900 delta = d->d1 - d->d2;
8901 else
8902 delta = 0;
8903
8904 if(delta)
8905 {
8906 oldpos = slp;
8907 oldval = d->d2;
8908
8909 //while (true) {
8910 for(; ;) //thank you, MSVC ~pkmnfrk
8911 {
8912 d->d2 = d->d2+delta;
8913 slpos = slratio*d->d2;
8914 slp = fixtoi(slpos);
8915
8916 if((slp != oldpos) || (d->d2 <= 0) || (d->d2 >= d->d1))
8917 break;
8918 }
8919
8920 if(d->d2 < 0)
8921 d->d2 = 0;
8922
8923 if(d->d2 > d->d1)
8924 d->d2 = d->d1;
8925
8926 retval = D_USED_CHAR;
8927
8928 if(d->d2 != oldval)
8929 {
8930 /* call callback function here */
8931 if(d->dp2)
8932 {
8933 proc = (SLIDER_TYPE)(d->dp2);
8934 retval |= (*proc)(d->dp3, d->d2);
8935 }
8936
8937 GUI_EVENT(d, geCHANGE_VALUE);
8938
8939 object_message(d, MSG_DRAW, 0);
8940 }
8941 }
8942
8943 break;
8944
8945 case MSG_WANTWHEEL:
8946 return 1;
8947
8948 case MSG_WHEEL:
8949 oldval = d->d2;
8950 d->d2 = MID(0, d->d2+c, d->d1);
8951
8952 if(d->d2 != oldval)
8953 {
8954 /* call callback function here */
8955 if(d->dp2)
8956 {
8957 proc = (SLIDER_TYPE)(d->dp2);
8958 retval |= (*proc)(d->dp3, d->d2);
8959 }
8960
8961 GUI_EVENT(d, geCHANGE_VALUE);
8962 object_message(d, MSG_DRAW, 0);
8963 retval |= D_REDRAWME;
8964 }
8965
8966 break;
8967
8968 case MSG_CLICK:
8969 /* track the mouse until it is released */
8970 mp = slp;
8971
8972 while(gui_mouse_b())
8973 {
8974 msx = gui_mouse_x();
8975 msy = gui_mouse_y();
8976 oldval = d->d2;
8977
8978 if(vert)
8979 mp = (d->y+d->h-hmar)-msy;
8980 else
8981 mp = msx-(d->x+hmar);
8982
8983 if(mp < 0)
8984 mp = 0;
8985
8986 if(mp > irange-hh)
8987 mp = irange-hh;
8988
8989 slpos = itofix(mp);
8990 slmax = fixdiv(slpos, slratio);
8991 newpos = fixtoi(slmax);
8992
8993 if(newpos != oldval)
8994 {
8995 d->d2 = newpos;
8996
8997 /* call callback function here */
8998 if(d->dp2 != NULL)
8999 {
9000 proc = (SLIDER_TYPE)(d->dp2);
9001 retval |= (*proc)(d->dp3, d->d2);
9002 }
9003
9004 GUI_EVENT(d, geCHANGE_VALUE);
9005 object_message(d, MSG_DRAW, 0);
9006 }
9007
9008 /* let other objects continue to animate */
9009 broadcast_dialog_message(MSG_IDLE, 0);
9010 update_hw_screen();
9011 }
9012
9013 break;
9014 }
9015
9016 return retval;
9017 }
9018
9019 // This is only used by jwin_check_proc and jwin_radio_proc.
9020 int32_t d_jwinbutton_proc(int32_t msg, DIALOG *d, int32_t)
9021 {
9022 BITMAP *gui_bmp;
9023 int32_t state1, state2;
9024 int32_t black;
9025 int32_t swap;
9026 int32_t g;
9027 ASSERT(d);
9028
9029 gui_bmp = screen;
9030
9031 switch(msg)
9032 {
9033 case MSG_DRAW:
9034 {
9035 if(d->flags & D_SELECTED)
9036 {
9037 g = 1;
9038 state1 = d->bg;
9039 state2 = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
9040 }
9041 else
9042 {
9043 g = 0;
9044 state1 = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
9045 state2 = d->bg;
9046 }
9047
9048 rectfill(gui_bmp, d->x+1+g, d->y+1+g, d->x+d->w-3+g, d->y+d->h-3+g, state2);
9049 rect(gui_bmp, d->x+g, d->y+g, d->x+d->w-2+g, d->y+d->h-2+g, state1);
9050 gui_textout_ex(gui_bmp, (char *)d->dp, d->x+d->w/2+g, d->y+d->h/2-text_height(font)/2+g, state1, -1, TRUE);
9051
9052 if(d->flags & D_SELECTED)
9053 {
9054 vline(gui_bmp, d->x, d->y, d->y+d->h-2, d->bg);
9055 hline(gui_bmp, d->x, d->y, d->x+d->w-2, d->bg);
9056 }
9057 else
9058 {
9059 black = makecol(0,0,0);
9060 vline(gui_bmp, d->x+d->w-1, d->y+1, d->y+d->h-2, black);
9061 hline(gui_bmp, d->x+1, d->y+d->h-1, d->x+d->w-1, black);
9062 }
9063
9064 if((d->flags & D_GOTFOCUS) &&
9065 (!(d->flags & D_SELECTED) || !(d->flags & D_EXIT)))
9066 dotted_rect(gui_bmp, d->x+1+g, d->y+1+g, d->x+d->w-3+g, d->y+d->h-3+g, state1, state2);
9067
9068 break;
9069 }
9070 case MSG_WANTFOCUS:
9071 return D_WANTFOCUS;
9072
9073 case MSG_KEY:
9074 {
9075 /* close dialog? */
9076 if(d->flags & D_EXIT)
9077 {
9078 return D_CLOSE;
9079 }
9080
9081 /* or just toggle */
9082 d->flags ^= D_SELECTED;
9083 GUI_EVENT(d, geTOGGLE);
9084 object_message(d, MSG_DRAW, 0);
9085 break;
9086 }
9087
9088 case MSG_CLICK:
9089 {
9090 /* what state was the button originally in? */
9091 state1 = d->flags & D_SELECTED;
9092
9093 swap = state1;
9094
9095 /* track the mouse until it is released */
9096 while(gui_mouse_b())
9097 {
9098 state2 = ((gui_mouse_x() >= d->x) && (gui_mouse_y() >= d->y) &&
9099 (gui_mouse_x() < d->x + d->w) && (gui_mouse_y() < d->y + d->h));
9100
9101 if(swap)
9102 state2 = !state2;
9103
9104 /* redraw? */
9105 bool should_redraw = false;
9106 if(((state1) && (!state2)) || ((state2) && (!state1)))
9107 {
9108 d->flags ^= D_SELECTED;
9109 GUI_EVENT(d, geTOGGLE);
9110 state1 = d->flags & D_SELECTED;
9111 object_message(d, MSG_DRAW, 0);
9112 should_redraw = true;
9113 }
9114
9115 /* let other objects continue to animate */
9116 int r = broadcast_dialog_message(MSG_IDLE, 0);
9117 if (r & D_REDRAWME) should_redraw = true;
9118
9119 if (should_redraw)
9120 {
9121 update_hw_screen();
9122 }
9123 }
9124
9125 if(d->dp3 != NULL)
9126 {
9127 //object_message(d, MSG_DRAW, 0);
9128 typedef int32_t (*funcType)(void);
9129 funcType func=reinterpret_cast<funcType>(d->dp3);
9130
9131 return func();
9132 }
9133
9134 /* should we close the dialog? */
9135 if(d->flags & D_EXIT)
9136 {
9137 return D_CLOSE;
9138 }
9139 break;
9140 }
9141 }
9142
9143 return D_O_K;
9144 }
9145
9146 //Misc bitmap drawing
9147 void draw_x(BITMAP* dest, int x1, int y1, int x2, int y2, int color)
9148 {
9149 line(dest, x1, y1, x2, y2, color);
9150 line(dest, x1, y2, x2, y1, color);
9151 }
9152
9153 void draw_check(BITMAP* dest, int x1, int y1, int x2, int y2, int c)
9154 {
9155 if(x2 < x1)
9156 zc_swap(x2,x1);
9157 if(y2 < y1)
9158 zc_swap(y2,y1);
9159 int x3 = ((x2-x1)/2)+x1;
9160 int y3 = y2-(x3-x1);
9161 line(dest, x1, y3, x3, y2, c);
9162 line(dest, x3, y2, x2, y1, c);
9163 }
9164
9165 void draw_checkerboard(BITMAP* dest, int x, int y, int sz, optional<int> cb_sz, int offx, int offy)
9166 {
9167 if(!cb_sz)
9168 cb_sz = sz/2;
9169 int ox = -x+offx, oy = -y+offy;
9170 ditherrectfill(dest, x, y, x+sz-1, y+sz-1, vc(CheckerCol1), dithChecker, *cb_sz, ox, oy, vc(CheckerCol2));
9171 }
9172
9173 int32_t d_vsync_proc(int32_t msg,DIALOG *d,int32_t c)
9174 {
9175 // This use to be what kept 60fps, but now render_timer_wait handles that.
9176 switch(msg)
9177 {
9178 case MSG_IDLE:
9179 {
9180 broadcast_dialog_message(MSG_VSYNC, c);
9181 break;
9182 }
9183 }
9184
9185 return D_O_K;
9186 }
9187
9188 //
9189
9190 void draw_checkbox(BITMAP *dest,int x,int y,int sz,bool value)
9191 {
9192 draw_checkbox(dest,x,y,sz,sz,value);
9193 }
9194 void draw_checkbox(BITMAP *dest,int x,int y,int wid,int hei,bool value)
9195 {
9196 jwin_draw_frame(dest, x, y, wid, hei, FR_DEEP);
9197 rectfill(dest, x+2, y+2, x+wid-3, y+hei-3, jwin_pal[jcTEXTBG]);
9198
9199 if(value)
9200 {
9201 line(dest, x+2, y+2, x+wid-3, y+hei-3, jwin_pal[jcTEXTFG]);
9202 line(dest, x+2, y+hei-3, x+wid-3, y+2, jwin_pal[jcTEXTFG]);
9203 }
9204 }
9205 void draw_dis_checkbox(BITMAP *dest,int x,int y,int wid,int hei,bool value)
9206 {
9207 jwin_draw_frame(dest, x, y, wid, hei, FR_DEEP);
9208
9209 if(value)
9210 {
9211 line(dest, x+2, y+2, x+wid-3, y+hei-3, jwin_pal[jcTEXTFG]);
9212 line(dest, x+2, y+hei-3, x+wid-3, y+2, jwin_pal[jcTEXTFG]);
9213 }
9214 }
9215
9216 bool do_scheckbox(BITMAP *dest,int x,int y,int sz,int &value, int xoffs, int yoffs)
9217 {
9218 return do_checkbox(dest,x,y,sz,sz,value,xoffs,yoffs);
9219 }
9220 bool do_checkbox(BITMAP *dest,int x,int y,int wid,int hei,int &value, int xoffs, int yoffs)
9221 {
9222 bool over=false;
9223
9224 while(gui_mouse_b())
9225 {
9226 if(isinRect(gui_mouse_x()-xoffs,gui_mouse_y()-yoffs,x,y,x+wid-1,y+hei-1))
9227 {
9228 if(!over)
9229 {
9230 value=value?0:1;
9231 draw_checkbox(dest,x,y,wid,hei,value!=0);
9232 over=true;
9233 update_hw_screen();
9234 }
9235 }
9236 else
9237 {
9238 if(over)
9239 {
9240 value=value?0:1;
9241 draw_checkbox(dest,x,y,wid,hei,value!=0);
9242 over=false;
9243 update_hw_screen();
9244 }
9245 }
9246 rest(1);
9247 }
9248
9249 return over;
9250 }
9251 bool do_checkbox_tx(BITMAP *dest,int x,int y,int wid,int hei,int &value, int txtoffs, int xoffs, int yoffs)
9252 {
9253 bool over=false;
9254
9255 while(gui_mouse_b())
9256 {
9257 if(isinRect(gui_mouse_x()-xoffs,gui_mouse_y()-yoffs,x,y,x+wid-1+txtoffs,y+hei-1))
9258 {
9259 if(!over)
9260 {
9261 value=value?0:1;
9262 draw_checkbox(dest,x,y,wid,hei,value!=0);
9263 over=true;
9264 update_hw_screen();
9265 }
9266 }
9267 else
9268 {
9269 if(over)
9270 {
9271 value=value?0:1;
9272 draw_checkbox(dest,x,y,wid,hei,value!=0);
9273 over=false;
9274 update_hw_screen();
9275 }
9276 }
9277 rest(1);
9278 }
9279
9280 return over;
9281 }
9282
9283 //box_out stuff
9284 static int32_t box_x = 0;
9285 static int32_t box_y = 0;
9286 static bool box_active=false;
9287 static int32_t box_store_x = 0;
9288 338 static FONT *box_title_font=font;
9289 338 static FONT *box_message_font=font;
9290 static int32_t box_style=0;
9291 static int32_t box_titlebar_height=0;
9292 static int32_t box_message_height=0;
9293 static uint8_t box_text_scale=1;
9294 static int32_t box_w=304;
9295 static int32_t box_h=176;
9296 static int32_t box_l=8;
9297 static int32_t box_r=312;
9298 static int32_t box_t=32;
9299 static int32_t box_b=208;
9300 static bool box_log=true;
9301 static char box_log_msg[480];
9302 static int32_t box_msg_pos=0;
9303 static int32_t box_store_pos=0;
9304
9305 int32_t onSnapshot2()
9306 {
9307 char buf[20];
9308 int32_t num=0;
9309
9310 do
9311 {
9312 sprintf(buf, "zelda%03d.bmp", ++num);
9313 }
9314 while(num<999 && exists(buf));
9315
9316 PALETTE temppal;
9317 get_palette(temppal);
9318 BITMAP *tempbmp=create_bitmap_ex(8,screen->w, screen->h);
9319 blit(screen,tempbmp,0,0,0,0,screen->w,screen->h);
9320 save_bitmap(buf,screen,temppal);
9321 destroy_bitmap(tempbmp);
9322 return D_O_K;
9323 }
9324
9325 void set_default_box_size()
9326 {
9327 int32_t screen_w = screen->w;
9328 int32_t screen_h = screen->h;
9329
9330 box_w=MIN(512, screen_w-16);
9331 box_h=MIN(256, (screen_h-64)&0xFFF0);
9332
9333 box_l=(screen_w-box_w)/2;
9334 box_t=(screen_h-box_h)/2;
9335 box_r=box_l+box_w;
9336 box_b=box_t+box_h;
9337 }
9338 /* resizes the box */
9339 void set_box_size(int32_t w, int32_t h)
9340 {
9341 int32_t screen_w = zq_screen_w;
9342 int32_t screen_h = zq_screen_h;
9343
9344 if(w <= 0) w = 512;
9345 if(h <= 0) h = 256;
9346 box_w=MIN(w, screen_w-16);
9347 box_h=MIN(h, (screen_h-64)&0xFFF0);
9348
9349 box_l=(screen_w-box_w)/2;
9350 box_t=(screen_h-box_h)/2;
9351 box_r=box_l+box_w;
9352 box_b=box_t+box_h;
9353 }
9354
9355 /* starts outputting a progress message */
9356 7 void box_start(int32_t style, const char *title, FONT *title_font, FONT *message_font, bool log, int32_t w, int32_t h, uint8_t scale)
9357 {
9358
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (is_headless())
9359 7 return;
9360
9361 box_text_scale=scale;
9362 box_style=style;
9363 box_title_font=(title_font!=NULL)?title_font:font;
9364 box_message_font=(message_font!=NULL)?message_font:font;
9365 box_message_height=text_height(box_message_font)*scale;
9366 box_titlebar_height=title?text_height(box_title_font)+2:0;
9367 set_box_size(w,h);
9368 /*
9369 box_w=BOX_W;
9370 box_h=BOX_H;
9371 box_l=BOX_L;
9372 box_r=BOX_R;
9373 box_t=BOX_T;
9374 box_b=BOX_B;
9375 */
9376 box_log=log;
9377 memset(box_log_msg, 0, 480);
9378 box_msg_pos=0;
9379 box_store_pos=0;
9380
9381 if(!box_active)
9382 popup_zqdialog_start();
9383 jwin_draw_win(screen, box_l, box_t, box_r-box_l, box_b-box_t, FR_WIN);
9384
9385 if(title!=NULL)
9386 {
9387 zc_swap(font,box_title_font);
9388 jwin_draw_titlebar(screen, box_l+3, box_t+3, box_r-box_l-6, 18, title, false);
9389 zc_swap(font,box_title_font);
9390 box_titlebar_height=18;
9391 }
9392
9393
9394 box_store_x = box_x = box_y = 0;
9395 box_active = true;
9396 box_t+=box_titlebar_height;
9397 box_h-=box_titlebar_height;
9398 box_log=log;
9399 memset(box_log_msg, 0, 480);
9400 box_msg_pos=0;
9401 box_store_pos=0;
9402 7 }
9403
9404 /* outputs text to the progress message */
9405 33490 void box_out(const char *msg)
9406 {
9407
1/2
✓ Branch 0 taken 33490 times.
✗ Branch 1 not taken.
33490 string remainder = "";
9408
1/2
✓ Branch 0 taken 33490 times.
✗ Branch 1 not taken.
33490 string temp(msg);
9409
9410
1/2
✓ Branch 0 taken 33490 times.
✗ Branch 1 not taken.
33490 if(box_active)
9411 {
9412 //do primitive text wrapping
9413 uint32_t i;
9414 for(i=0; i<temp.size(); i++)
9415 {
9416 int32_t length = text_length(box_message_font,temp.substr(0,i).c_str())*box_text_scale;
9417
9418 if(length > box_r-box_l-16)
9419 {
9420 i = zc_max(i-1,0);
9421 break;
9422 }
9423 }
9424
9425 set_clip_rect(screen, box_l+8, box_t+1, box_r-8, box_b-1);
9426 if(box_text_scale == 1)
9427 textout_ex(screen, box_message_font, temp.substr(0,i).c_str(), box_l+8+box_x, box_t+(box_y+1)*box_message_height, gui_fg_color, gui_bg_color);
9428 else
9429 {
9430 int32_t length = text_length(box_message_font,temp.substr(0,i).c_str());
9431 BITMAP* tempbit = create_bitmap_ex(8, length, box_message_height);
9432 clear_bitmap(tempbit);
9433 textout_ex(tempbit, box_message_font, temp.substr(0,i).c_str(), 0, 0, gui_fg_color, gui_bg_color);
9434 stretch_blit(tempbit, screen, 0, 0, length, box_message_height/box_text_scale, box_l+8+box_x, box_t+(box_y+1)*box_message_height, length*box_text_scale, box_message_height);
9435 destroy_bitmap(tempbit);
9436 }
9437 set_clip_rect(screen, 0, 0, screen->w-1, screen->h-1);
9438 remainder = temp.substr(i,temp.size()-i);
9439 }
9440
9441
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33490 times.
33490 if(box_log)
9442 {
9443 33490 sprintf(box_log_msg+box_msg_pos, "%s", msg);
9444 33490 }
9445
9446
1/2
✓ Branch 0 taken 33490 times.
✗ Branch 1 not taken.
33490 box_x += text_length(box_message_font, msg);
9447 33490 box_msg_pos+=(int32_t)strlen(msg);
9448
9449
2/4
✓ Branch 0 taken 33490 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 33490 times.
33490 if(remainder != "")
9450 {
9451 bool oldlog = box_log;
9452 box_log = false;
9453 box_eol();
9454 box_out(remainder.c_str());
9455 box_log = oldlog;
9456 }
9457
9458 // For web, always call update_hw_screen because it yields to the main thread,
9459 // which makes long running tasks like loading a quest not block the main thread,
9460 // which would make SFX sound awful on the title screen.
9461
3/6
✓ Branch 0 taken 33490 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33490 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 33490 times.
33490 if (box_active || is_web())
9462 update_hw_screen();
9463 33490 }
9464
9465 /* calls box_out, and box_eol for newlines */
9466 void box_out_nl(const char *msg)
9467 {
9468 string line;
9469 istringstream reader(msg);
9470 while (getline(reader, line))
9471 {
9472 box_out(line.c_str());
9473 box_eol();
9474 }
9475 }
9476
9477 /* remembers the current x position */
9478 160 void box_save_x()
9479 {
9480
1/2
✓ Branch 0 taken 160 times.
✗ Branch 1 not taken.
160 if(box_active)
9481 {
9482 box_store_x=box_x;
9483 }
9484
9485 160 box_store_pos=box_msg_pos;
9486 160 }
9487
9488 /* remembers the current x position */
9489 156 void box_load_x()
9490 {
9491
1/2
✓ Branch 0 taken 156 times.
✗ Branch 1 not taken.
156 if(box_active)
9492 {
9493 box_x=box_store_x;
9494 }
9495
9496 156 box_msg_pos=box_store_pos;
9497 156 }
9498
9499 /* outputs text to the progress message */
9500 16972 void box_eol()
9501 {
9502
1/2
✓ Branch 0 taken 16972 times.
✗ Branch 1 not taken.
16972 if(box_active)
9503 {
9504 box_x = 0;
9505 box_y++;
9506
9507 if((box_y+2)*box_message_height >= box_h)
9508 {
9509 blit(screen, screen, box_l+8, box_t+(box_message_height*2), box_l+8, box_t+(box_message_height), box_w-16, box_y*box_message_height);
9510 rectfill(screen, box_l+8, box_t+box_y*box_message_height, box_l+box_w-8, box_t+(box_y+1)*box_message_height, gui_bg_color);
9511 box_y--;
9512 }
9513 }
9514
9515 16972 box_msg_pos = 0;
9516
9517
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16972 times.
16972 if(box_log)
9518 {
9519 16972 al_trace("%s", box_log_msg);
9520 16972 al_trace("\n");
9521 16972 memset(box_log_msg, 0, 480);
9522 16972 }
9523
9524
1/2
✓ Branch 0 taken 16972 times.
✗ Branch 1 not taken.
16972 if (box_active)
9525 update_hw_screen();
9526 16972 }
9527
9528 /* ends output of a progress message */
9529 641 void box_end(bool pause)
9530 {
9531
1/2
✓ Branch 0 taken 641 times.
✗ Branch 1 not taken.
641 if(box_active)
9532 {
9533 if(pause)
9534 {
9535 box_eol();
9536 box_pause();
9537 }
9538
9539 box_active = false;
9540 popup_zqdialog_end();
9541 }
9542 641 }
9543
9544 /* pauses box output */
9545 void box_pause()
9546 {
9547 if(box_active)
9548 {
9549 box_save_x();
9550 box_out("-- press a key --");
9551
9552 while(gui_mouse_b()) rest(1);
9553 while(!(keypressed() || gui_mouse_b())) rest(1);
9554 while(gui_mouse_b()) rest(1);
9555
9556 clear_keybuf();
9557 box_load_x();
9558 }
9559 }
9560